diff --git a/.github/workflows/publisher-spec-sync.yaml b/.github/workflows/publisher-spec-sync.yaml new file mode 100644 index 0000000..8545ad3 --- /dev/null +++ b/.github/workflows/publisher-spec-sync.yaml @@ -0,0 +1,81 @@ +name: Publisher Spec Sync + +# The publisher document is generated from the consumption specification plus +# spec/publisher/overlay.yaml. It was previously a hand-maintained copy and +# drifted four minor versions behind, carrying duplicate definitions of shared +# objects under different names. This job fails if it drifts again. + +on: + push: + branches: ['main'] + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + check: + name: Publisher spec is in sync + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install + working-directory: spec/publisher + run: npm ci || npm install + + - name: Rebuild and compare + working-directory: spec/publisher + run: npm run check + + - name: Lint the generated document + working-directory: spec/publisher + # The consumption specification currently carries 24 lint errors + # of its own (23 missing operation summaries, one OpenAPI 3.0 + # `nullable`). The overlay adds none, so this compares the two + # counts rather than requiring zero, and fails only if the + # publisher document is worse than the spec it is built from. + run: | + set -o pipefail + # `redocly lint` exits non-zero whenever it reports an error, + # and both documents report 24, so its exit status says + # nothing the count does not. Discard it: this step runs under + # `bash -e`, and without the `|| true` the pipeline's inherited + # failure aborts the assignment below before anything is + # compared. That is not a hypothetical: it is why this step + # failed on every run before this comment existed. + count() { + { npx redocly lint "$1" --format=json 2>/dev/null || true; } | node -e ' + let s = "" + process.stdin.on("data", d => s += d).on("end", () => { + // No output means redocly itself failed. Counting that + // as zero errors would leave the gate below passing + // while checking nothing. + if (!s.trim()) { + console.error("redocly produced no output for the document under lint") + process.exit(1) + } + const j = JSON.parse(s) + console.log(j.problems.filter(p => p.severity === "error").length) + })' + } + base=$(count ../openapi.yaml) + pub=$(count openapi.yaml) + echo "consumption errors: $base, publisher errors: $pub" + if [ "$pub" -gt "$base" ]; then + echo "The publication overlay introduced $((pub - base)) new error(s)." + # `|| true` so errexit does not cut the diagnostic short + # before the explicit exit below. + npx redocly lint openapi.yaml || true + exit 1 + fi diff --git a/.gitignore b/.gitignore index 981765e..1b408c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ out/* .DS_Store +node_modules/ diff --git a/contributors.md b/contributors.md index 9769ffb..653f20a 100644 --- a/contributors.md +++ b/contributors.md @@ -9,6 +9,7 @@ work during our meetings and workshops. They are noted here in alphabetic order: * Anthony Harrison, APH10, United Kingdom * Olle E. Johansson, Project lead, Edvina AB, Sweden, oej@edvina.net +* Christopher Langton * Mark Symons * Paul Horton, Sonatype Inc., paul.horton@owasp.org, [@madaph](https://github.com/madpah) * Pavel Shukhman, Reliza, Canada, pavel@reliza.io @@ -16,4 +17,3 @@ work during our meetings and workshops. They are noted here in alphabetic order: * Steve Springett * Valerio Mulas * Viktor Petersson, sbomify, United Kingdom, hello@sbomify.com - diff --git a/spec/openapi.yaml b/spec/openapi.yaml index 79f85c8..04acc09 100644 --- a/spec/openapi.yaml +++ b/spec/openapi.yaml @@ -1754,6 +1754,22 @@ components: security: - bearerAuth: [] - basicAuth: [] + # Authentication is optional, not absent. + # + # Every operation in this document is a read, and discovery has no step at + # which a credential could be obtained: a consumer takes the domain out of a + # TEI, fetches that host's discovery document, and calls the root it names. + # Requiring a credential of all three would close the only entry point the + # specification defines, so a server MUST be able to answer an anonymous + # request. What it answers with is a separate question: an object the caller + # is not entitled to is `OBJECT_UNKNOWN`, exactly as it is for an object that + # does not exist. + # + # A caller that does present a credential has asserted an identity, and a + # server MUST verify it rather than quietly downgrading to anonymous: an + # expired key that silently returns only public data is indistinguishable + # from a publisher having withdrawn everything. + - {} tags: - name: TEA Product - name: TEA Product Release diff --git a/spec/publisher/README.md b/spec/publisher/README.md index c1c7c4f..d0e99cb 100644 --- a/spec/publisher/README.md +++ b/spec/publisher/README.md @@ -3,4 +3,212 @@ This specification will be a recommended TEA publisher API. The TEA specification is focused on the consumption API, which is the base of conformance with the specification. -NOTE: This is a copy of the OpenAPI specification including both consumption and publication APIs. +`openapi.yaml` here is **generated**. It is the consumption specification plus +the publication operations in `overlay.yaml`, merged by `build.mjs`. + +```sh +cd spec/publisher +npm install +npm run build # regenerate openapi.yaml +npm run check # fail if it has drifted from spec/openapi.yaml +npm run lint # redocly +``` + +## Why it is generated + +It used to be a hand-maintained copy, and it drifted, as copies do. While the +consumption API moved to 0.4.0 the copy still carried schemas from 0.0.3, under +different names: `artifactFormat` beside the real `artifact-format`, `typeUuid` +beside `uuid`, a private `artifactChecksum` beside `checksum`. A combined +document then holds two definitions of the same concept, each free to move +independently, with nothing to say which one a publisher should believe. + +Generating it removes the possibility rather than the symptom. Everything shared +is a `$ref` into the consumption specification's own definitions, so there is +exactly one definition of a product, a checksum or an artifact format, and the +publisher version *is* the consumer version because `build.mjs` copies it rather +than letting anyone choose one. + +`build.mjs` refuses to build if `overlay.yaml` declares a schema, parameter, +response, request body or path method that the consumption specification already +owns. That is the drift check with teeth: the overlay may only add. + +## Alignment corrections made when this was regenerated + +- **Releases are split.** The draft had a single `/release`, but the consumption + API distinguishes a product release from a component release. There are now + `/productRelease` and `/componentRelease`, matching `productRelease` and + `release` in the consumption schemas. +- **Collections are addressed through their release.** The consumption + specification states that a collection's UUID matches the release it belongs + to, and that an update only changes the version, so a collection is not an + independently created object. Publishing one is now + `PUT /productRelease/{uuid}/collection` (and the component equivalent), which + publishes the next version, rather than `POST /collection`. +- **Errors reuse the consumption envelope.** The draft returned + `application/json: {}`, an empty schema saying nothing about failures. + `publisher-error-response` uses the same `{ error: }` shape as + `error-response`, over an enumeration that repeats the consumption values + (`OBJECT_UNKNOWN`, `OBJECT_NOT_SHAREABLE`) and adds the ones only a writer can + hit, so a client branches on one enumeration rather than two. +- **`distribution` was renamed `access-policy`.** The consumption specification + already uses `release-distribution` for something else entirely: a + downloadable build with its own URL and checksums. Reusing the word for access + control in a combined document would have been actively misleading. +- **The invalid delete indirection is gone.** `components.operations` is not a + field OpenAPI defines, so the three `$ref`s pointing into it never resolved + and every delete declared no responses at all. A generator reading the old + draft produced deletes that returned nothing. +- **A product release can state its components.** The consumption API lists + `components` among `productRelease`'s required members, and the draft's + create body had no way to set it, so every release a conformant publisher + could produce had to be served with an empty list, which is a claim about the + product rather than a gap in the record. +- **An artifact can say which distributions it describes.** `distributionIds` + exists in the consumption `artifact` and was unreachable from the publication + API. It matters where an SBOM is not one document: a Windows installer and a + source tarball of the same release have different contents. + +## What the publication overlay adds + +### Artifacts + +The draft could create products, components, releases and collections but had no +way to publish the artifact carrying the SBOM, VEX or attestation the exchange +exists to move. + +Registering an artifact and uploading its bytes are separate operations. An SBOM +is routinely tens of megabytes, and a publisher who must resend all of it to +correct one metadata field will in practice not correct the field. Content is +`PUT` per format in its own media type rather than base64 inside JSON, which +would inflate it by a third for no benefit. + +Stored bytes are immutable: a checksum a consumer already recorded must not +begin describing different content, so replacing content means a new format or a +new artifact. Uploads accept `Content-Digest` (RFC 9530) and a mismatch is +rejected, which is what makes a retry safe: a truncated transfer fails loudly +instead of publishing corruption under a checksum claiming otherwise. + +### Signatures + +`signatures/signature.md` asks for an indication of the hash algorithm, an +indicator of the certificate used, and the intermediate and signing +certificates. The consumption API exposes only a `signatureUrl`, so a consumer +must infer the scheme from the bytes before it can verify anything. +`artifact-signature` records the scheme, algorithm, key identifier, certificate +and chain, and the transparency-log entry where the scheme has one. That is +what turns a signature from something that exists into something checkable. + +### Access policy + +TEA describes how transparency data is fetched, not who is entitled to fetch it. +That is a reasonable boundary for a consumption API and an impossible one for a +publication API, where the same server holds material that is deliberately +public, material shared with named counterparties under agreement, and material +that is purely internal. Absent an answer, every publisher invents one. + +Three visibilities (`private`, `shared` to named organisation UUIDs with an +optional expiry, and `public`), plus `publishTo` for mirroring to other TEA +servers. Two rules carry the weight: + +- **The narrowest declaration on the chain wins, not the nearest.** An artifact + sits under its collection, a collection under its release, a release under its + product, and the policy in force is the most restrictive declared anywhere + between the object and the root. `ACCESS_WIDENS_PARENT` rejects a declaration + that is too wide when it is written, which is not the same guarantee: it says + nothing about a parent narrowed afterwards. Under nearest-wins, an artifact + that had declared `public` stays public after its product is set to `private`, + so marking a product private would be a statement about one row. + + Where several levels declare `shared`, entitlements intersect and the earliest + expiry applies, because a grant on a child cannot create an entitlement its + parent withheld. Descendants' declarations are never rewritten, so widening a + product back restores each descendant to its own declaration and no further. + That is what makes a temporary embargo reversible. +- **`public` is one-way in practice.** No later request recalls what has already + been fetched, so that transition requires `confirm=public` rather than being + an ordinary field update. The mechanism is named, not merely asked for: an + unspecified requirement is one every publisher satisfies differently, which + is the failure this document exists to avoid. + +This needs no new consumer-side behaviour: a consumer denied by the policy gets +the consumption specification's existing `OBJECT_NOT_SHAREABLE`, which is +already in `unknown-error-type`. + +`GET /accessPolicy/{uuid}` reports what an object *declares* alongside what it +*effectively* has and which ancestor that came from. The gap between declared +and effective is where accidental disclosure hides, so it is reported rather +than left to be reconstructed. + +Mirroring to other TEA servers is `publishTo`, naming targets registered +through `/publicationTargets`. Registration is separate from use because a +credential is involved, and because handing an object to another server is a +decision that outlives the object: once a copy lands there, this server's +policy no longer governs it. Mirroring is asynchronous and never blocks the +local write: refusing to record a publisher's own release because a mirror is +unreachable would make every target a single point of failure for publication +itself. State is reported per target on the object's access policy, and a +server that does not mirror answers `MIRRORING_UNSUPPORTED` rather than +accepting the request and doing nothing. + +### The publisher read surface + +`GET /publications` and `GET /publications/{uuid}/releases` report what this +organisation has published together with the policy in force for each. + +The consumption API cannot answer this. It answers what a *reader* is entitled +to see, and the thing a publisher most needs to verify, that something private +really is private, is exactly what a consumption response cannot show, because +an object correctly withheld and an object that was never created look +identical from outside. + +### Idempotency + +`Idempotency-Key` on creates. Publication runs in pipelines, and pipelines +retry. Without it a timeout that actually succeeded yields a second object on +the next attempt, a duplicate found by a consumer rather than by the publisher. + +## Known lint baseline + +`npm run lint` reports 24 errors. All 24 are inherited: linting +`spec/openapi.yaml` on its own reports exactly the same 24, so the publication +overlay contributes none. + +- 23 × `operation-summary`: consumption operations have no `summary`. +- 1 × `struct`: `pagination-details.nextPageToken` uses `nullable: false`, + which OpenAPI 3.1 removed in favour of a type union. + +These are worth fixing in the consumption specification rather than papering +over here, since patching them in this fork would put it at odds with upstream +on a file upstream owns. + +## The one change this makes to the consumption specification + +`spec/openapi.yaml` gains an empty alternative in its global `security`, so +authentication is optional rather than mandatory. + +Without it the publication API cannot mean what it says. `visibility: public` +is defined as "readable without authentication", and the discovery sequence a +consumer follows (take the domain out of a TEI, fetch that host's discovery +document, call the root it names) has no step at which a credential could be +obtained. A specification that requires one on every operation closes the only +entry point it defines, and any server that actually serves a public object +anonymously is then non-conformant for doing the right thing. + +It is a widening, so no conformant client or server is broken by it: a server +may still refuse every anonymous request, and one that answers is now allowed +to. The publication operations are unaffected: `build.mjs` gives every +operation the overlay contributes an explicit `bearerAuth`/`basicAuth` +requirement, so anonymous writes are never conformant. + +## Open questions + +- **Artifact versions.** The consumption API addresses artifacts as + `/artifact/{uuid}/{artifactVersion}`, but the overlay's create and update do + not yet say how a publisher advances that version. The rule is probably that + content is immutable and a new revision is a new version, but "probably" is + not a specification. +- **Mirror authentication is one-directional.** A target is registered with a + credential this server presents. Nothing says how the receiving server + decides whether to accept a mirrored object, or how it records that the + object came from elsewhere rather than being published to it directly. diff --git a/spec/publisher/build.mjs b/spec/publisher/build.mjs new file mode 100644 index 0000000..bfe9b54 --- /dev/null +++ b/spec/publisher/build.mjs @@ -0,0 +1,177 @@ +#!/usr/bin/env node +// Build spec/publisher/openapi.yaml from the consumption specification plus a +// publication overlay. +// +// The publisher document used to be a hand-maintained copy of the consumption +// spec. It drifted, as copies do: while the consumption API reached 0.4.0 the +// copy was still carrying schemas from 0.0.3, under different names: +// `artifactFormat` beside the real `artifact-format`, `typeUuid` beside `uuid`, +// a private `artifactChecksum` beside `checksum`. A combined document then has +// two definitions of the same concept, each free to move independently, and +// nothing in it says which one a publisher should believe. +// +// Generating the document removes the possibility. Everything shared is a +// `$ref` into the consumption spec's own definitions, so there is exactly one +// definition of a product, a checksum or an artifact format, and the publisher +// version is the consumer version by construction. +// +// node spec/publisher/build.mjs # regenerate openapi.yaml +// node spec/publisher/build.mjs --check # fail (exit 1) if it has drifted +// +// Run --check in CI after any change to spec/openapi.yaml. + +import { readFileSync, writeFileSync } from 'node:fs' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import yaml from 'js-yaml' + +const here = dirname(fileURLToPath(import.meta.url)) +const consumerPath = resolve(here, '..', 'openapi.yaml') +const overlayPath = resolve(here, 'overlay.yaml') +const outPath = resolve(here, 'openapi.yaml') + +const consumer = yaml.load(readFileSync(consumerPath, 'utf8')) +const overlay = yaml.load(readFileSync(overlayPath, 'utf8')) + +/** + * Merge the overlay onto the consumption document. + * + * Deliberately shallow-but-structured rather than a generic deep merge: the + * overlay may only ADD. If it defines a key the consumption spec already + * defines, that is drift reappearing, the publisher redefining something the + * consumer owns, so it is a build failure rather than a silent overwrite. + */ +const collisions = [] + +// The consumption document's global `security` now offers an anonymous +// alternative, because every operation in it is a read and discovery has no +// step at which a credential could be obtained. +// +// That must not reach the publication operations. Inheriting the global list +// would make anonymous writes conformant, which is the opposite of what the +// access policy exists to say, so every operation the overlay contributes +// declares its own requirement here. Stated once, rather than repeated on +// twenty operations where one omission would be a silent hole. +const WRITE_SECURITY = [{ bearerAuth: [] }, { basicAuth: [] }] + +// A path item also holds `parameters`, `summary` and `$ref`, none of which take +// a security requirement. +const HTTP_METHODS = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']) + +function requireCredential(method, op) { + // An overlay operation may still set `security` itself; this only supplies + // the default. + if (HTTP_METHODS.has(method)) op.security ??= WRITE_SECURITY + return op +} + +function mergeSection(target, source, path) { + for (const [key, value] of Object.entries(source ?? {})) { + if (target[key] === undefined) { + if (path === 'paths') { + for (const [method, op] of Object.entries(value)) requireCredential(method, op) + } + target[key] = value + continue + } + // Path items are the one place both documents legitimately contribute: + // the consumer defines GET /product/{uuid}, the publisher adds PATCH + // and DELETE to the same path. Merge per method, and still refuse to + // redefine a method the consumer already declared. + if (path === 'paths') { + for (const [method, op] of Object.entries(value)) { + if (target[key][method] !== undefined) { + collisions.push(`${path}.${key}.${method}`) + continue + } + target[key][method] = requireCredential(method, op) + } + continue + } + collisions.push(`${path}.${key}`) + } +} + +// info: the publisher document describes the same API version as the consumer. +// The version is copied, never chosen, so the two cannot report different +// numbers for the same object model. +consumer.info = { + ...consumer.info, + title: 'Transparency Exchange API', + summary: 'The OWASP Transparency Exchange API specification for consumers and publishers', + description: [ + consumer.info.description?.trim(), + '', + 'This document is the consumption specification plus the publication', + 'operations. Everything the two share, whether products, components,', + 'releases, collections, artifacts, checksums or identifiers, has a single', + 'definition,', + 'taken from the consumption specification, so a publisher and a consumer', + 'cannot hold different ideas of the same object.', + '', + 'Generated by spec/publisher/build.mjs. Do not edit by hand: edit', + 'spec/publisher/overlay.yaml, or the consumption specification, and rebuild.', + ].filter(v => v !== undefined).join('\n'), +} + +mergeSection(consumer.paths, overlay.paths, 'paths') + +for (const section of ['schemas', 'parameters', 'responses', 'requestBodies', 'securitySchemes']) { + consumer.components[section] ??= {} + mergeSection(consumer.components[section], overlay.components?.[section], `components.${section}`) +} + +// Tags are a list, not a map. +const existingTags = new Set((consumer.tags ?? []).map(t => t.name)) +consumer.tags = [ + ...(consumer.tags ?? []), + ...(overlay.tags ?? []).filter(t => !existingTags.has(t.name)), +] + +if (collisions.length) { + console.error('The overlay redefines objects the consumption specification already owns:') + for (const c of collisions) console.error(` ${c}`) + console.error('\nRemove them from the overlay and $ref the consumption definition instead.') + process.exit(1) +} + +const banner = `# GENERATED FILE - do not edit by hand. +# +# Built by spec/publisher/build.mjs from: +# spec/openapi.yaml (the consumption specification, version ${consumer.info.version}) +# spec/publisher/overlay.yaml (the publication operations) +# +# Regenerate with: node spec/publisher/build.mjs +` + +const body = yaml.dump(consumer, { + lineWidth: 100, + noRefs: true, + quotingType: '"', +}) + +const out = `${banner}\n${body}` + +if (process.argv.includes('--check')) { + let current = '' + try { + current = readFileSync(outPath, 'utf8') + } catch { + current = '' + } + if (current !== out) { + console.error('spec/publisher/openapi.yaml has drifted from the consumption specification.') + console.error('Run: node spec/publisher/build.mjs') + process.exit(1) + } + console.log(`publisher spec is in sync with consumption specification ${consumer.info.version}.`) + process.exit(0) +} + +writeFileSync(outPath, out) +console.log( + `Wrote ${outPath}\n` + + ` version ${consumer.info.version}, ` + + `${Object.keys(consumer.paths).length} paths, ` + + `${Object.keys(consumer.components.schemas).length} schemas.`, +) diff --git a/spec/publisher/openapi.json b/spec/publisher/openapi.json deleted file mode 100644 index 538763c..0000000 --- a/spec/publisher/openapi.json +++ /dev/null @@ -1,1516 +0,0 @@ -{ - "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base", - "openapi": "3.1.1", - "info": { - "title": "Transparency Exchange API", - "summary": "Transparency Exchange API specification for consumers and publishers", - "description": "TBC", - "contact": { - "name": "TEA Working Group", - "email": "TBC", - "url": "https://github.com/CycloneDX/transparency-exchange-api" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/CycloneDX/transparency-exchange-api/blob/main/LICENSE" - }, - "version": "0.0.2" - }, - "servers": [ - { - "url": "http://localhost/tea/v1", - "description": "Local development" - } - ], - "paths": { - "/product/{tei_urn}": { - "get": { - "description": "Returns the corresponding leafs for a given TEI URN", - "operationId": "getTeaProduct", - "parameters": [ - { - "$ref": "#/components/parameters/tei_urn" - } - ], - "responses": { - "200": { - "description": "Requested TEA Product found and returned", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_product" - } - } - } - }, - - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - - }, - "tags": [ - "TEA Product" - ] - }, - "patch": { - "description": "Update an existing TEA Product entry", - "operationId": "updateTeaProduct", - "parameters": [ - { - "$ref": "#/components/parameters/tea_product_identifier" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "product_name": { - "type": "string" - }, - "barcode": { - "type": "string", - "description": "Barcode" - }, - "sku": { - "type": "string", - "description": "Product SKU" - }, - "vendor_uuid": { - "$ref": "#/components/schemas/type_uuid", - "description": "Vendor UUID" - }, - "purl": { - "type": "string", - "description": "Package URL (PURL)" - } - } - }, - "examples": { - "basic": { - "summary": "Basic product update", - "value": { - "product_name": "Updated Product Name", - "barcode": "123456789012", - "sku": "PROD-001", - "vendor_uuid": "123e4567-e89b-12d3-a456-426614174000", - "purl": "pkg:generic/example@1.0.0" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "TEA Product updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_product" - } - } - } - }, - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Product" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - }, - "delete": { - "description": "Delete a TEA Product entry", - "operationId": "deleteTeaProduct", - "parameters": [ - { - "$ref": "#/components/parameters/tea_product_identifier" - } - ], - "$ref": "#/components/operations/standard_delete", - "tags": [ - "TEA Product" - ] - } - }, - "/product": { - "get": { - "description": "Returns a list of TEA Products", - "operationId": "listTeaProducts", - "parameters": [ - { - "$ref": "#/components/parameters/standard_pagination" - } - ], - "responses": { - "200": { - "description": "List retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/paginated_product_list" - } - } - } - }, - "$ref": "#/components/responses/standard_errors" - } - }, - "post": { - "description": "Create TEA Product entry for the supplied product identifier", - "operationId": "createTeaProduct", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "product_name": { - "type": "string" - }, - "barcode": { - "type": "string", - "description": "Barcode" - }, - "sku": { - "type": "string", - "description": "Product SKU" - }, - "vendor_uuid": { - "$ref": "#/components/schemas/type_uuid", - "description": "Vendor UUID" - }, - "purl": { - "type": "string", - "description": "Package URL (PURL)" - } - }, - "required": [ - "product_name" - ] - }, - "examples": { - "basic": { - "summary": "Basic product creation", - "value": { - "product_name": "Example Product" - } - }, - "full": { - "summary": "Full product creation with all fields", - "value": { - "product_name": "Complete Product Example", - "barcode": "123456789012", - "sku": "PROD-001", - "vendor_uuid": "123e4567-e89b-12d3-a456-426614174000", - "purl": "pkg:generic/example@1.0.0" - } - } - } - } - } - }, - "responses": { - "201": { - "description": "TEA Product created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "product_name": { - "type": "string" - }, - "barcode": { - "type": "string" - }, - "sku": { - "type": "string" - }, - "vendor_uuid": { - "$ref": "#/components/schemas/type_uuid" - }, - "purl": { - "type": "string" - } - }, - "required": [ - "identifier", - "product_name" - ] - } - } - } - }, - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Product" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - } - }, - "/leaf": { - "post": { - "description": "Create a new TEA Leaf entry", - "operationId": "createTeaLeaf", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "tea_product_identifier": { - "type": "string" - }, - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "pre_release": { - "type": "boolean" - } - }, - "required": [ - "tea_product_identifier", - "product_version", - "release_date", - "pre_release" - ] - }, - "examples": { - "basic": { - "summary": "Basic leaf creation", - "value": { - "tea_product_identifier": "123e4567-e89b-12d3-a456-426614174000", - "product_version": "1.0.0", - "release_date": "2024-03-20T15:30:00Z", - "pre_release": false - } - } - } - } - } - }, - "responses": { - "201": { - "description": "TEA Leaf created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_leaf" - } - } - } - }, - "400": { - "description": "Invalid parameters", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Leaf" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - } - }, - "/leaf/{tea_leaf_identifier}": { - "get": { - "description": "Get the TEA Leaf that describes the Version of a Product", - "operationId": "getTeaLeaf", - "parameters": [ - { - "$ref": "#/components/parameters/tea_leaf_identifier" - } - ], - "responses": { - "200": { - "description": "Requested TEA Leaf found and returned", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_leaf" - } - } - } - }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Leaf" - ] - }, - "patch": { - "description": "Update an existing TEA Leaf entry", - "operationId": "updateTeaLeaf", - "parameters": [ - { - "$ref": "#/components/parameters/tea_leaf_identifier" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "product_name": { - "type": "string" - }, - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "pre_release": { - "type": "boolean" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "TEA Leaf updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_leaf" - } - } - } - }, - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Leaf" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - }, - "delete": { - "description": "Delete a TEA Leaf entry", - "operationId": "deleteTeaLeaf", - "parameters": [ - { - "$ref": "#/components/parameters/tea_leaf_identifier" - } - ], - "$ref": "#/components/operations/standard_delete", - "tags": [ - "TEA Leaf" - ] - } - }, - "/collection": { - "post": { - "description": "Create a new TEA Collection", - "operationId": "createTeaCollection", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "tea_leaf_identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "product_name": { - "type": "string" - }, - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "reason": { - "$ref": "#/components/schemas/type_collection_reason" - }, - "artifacts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "$ref": "#/components/schemas/type_tea_collection_artifact_type" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "objects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "media_type": { - "type": "string" - }, - "artifact_url": { - "type": "string", - "format": "uri" - }, - "artifact_size_in_bytes": { - "type": "integer", - "format": "int64" - }, - "artifact_checksum": { - "type": "string", - "description": "The checksum value" - }, - "artifact_checksum_type": { - "type": "string", - "description": "The algorithm used to generate the checksum", - "enum": [ - "SHA512", - "SHA384", - "SHA256", - "SHA224", - "SHA1", - "MD5", - "BLAKE2b-512", - "BLAKE2s-256", - "BLAKE3" - ], - "default": "SHA256" - }, - "signature_url": { - "type": "string", - "format": "uri" - } - }, - "required": [ - "description", - "media_type", - "artifact_url", - "artifact_size_in_bytes", - "artifact_checksum", - "artifact_checksum_type" - ] - } - } - }, - "required": [ - "name", - "type", - "author", - "objects" - ] - } - } - }, - "required": [ - "tea_leaf_identifier", - "product_name", - "product_version", - "release_date", - "author", - "reason" - ] - }, - "examples": { - "basic": { - "summary": "Basic collection creation", - "value": { - "tea_leaf_identifier": "123e4567-e89b-12d3-a456-426614174000", - "product_name": "Example Product", - "product_version": "1.0.0", - "release_date": "2024-03-20T15:30:00Z", - "author": { - "name": "John Doe", - "email": "john.doe@example.com", - "organization": "Example Org" - }, - "reason": "New Product Release", - "artifacts": [ - { - "name": "Example TEA Artifact", - "type": "bom", - "author": { - "name": "John Doe", - "email": "john.doe@example.com", - "organization": "Example Org" - }, - "objects": [ - { - "description": "Example SBOM", - "media_type": "application/json", - "artifact_url": "https://example.com/sbom.json", - "artifact_size_in_bytes": 1024, - "artifact_checksum": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", - "artifact_checksum_type": "SHA256" - } - ] - } - ] - } - } - } - } - } - }, - "responses": { - "201": { - "description": "TEA Collection created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_collection" - } - } - } - }, - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Collection" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - } - }, - "/collection/{tea_collection_identifier}": { - "get": { - "description": "Get a TEA Collection by it's Identifier", - "operationId": "getTeaCollection", - "parameters": [ - { - "$ref": "#/components/parameters/tea_collection_identifier" - } - ], - "responses": { - "200": { - "description": "Requested TEA Collection found and returned", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_collection" - } - } - } - }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Collection" - ] - }, - "patch": { - "description": "Update an existing TEA Collection", - "operationId": "updateTeaCollection", - "parameters": [ - { - "$ref": "#/components/parameters/tea_collection_identifier" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "product_name": { - "type": "string" - }, - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "reason": { - "$ref": "#/components/schemas/type_collection_reason" - }, - "artifacts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "$ref": "#/components/schemas/type_tea_collection_artifact_type" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "objects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "media_type": { - "type": "string" - }, - "artifact_url": { - "type": "string", - "format": "uri" - }, - "artifact_size_in_bytes": { - "type": "integer", - "format": "int64" - }, - "artifact_checksum": { - "type": "string", - "description": "The checksum value" - }, - "artifact_checksum_type": { - "type": "string", - "description": "The algorithm used to generate the checksum", - "enum": [ - "SHA512", - "SHA384", - "SHA256", - "SHA224", - "SHA1", - "MD5", - "BLAKE2b-512", - "BLAKE2s-256", - "BLAKE3" - ], - "default": "SHA256" - }, - "signature_url": { - "type": "string", - "format": "uri" - } - }, - "required": [ - "description", - "media_type", - "artifact_url", - "artifact_size_in_bytes", - "artifact_checksum", - "artifact_checksum_type" - ] - } - } - }, - "required": [ - "name", - "type", - "author", - "objects" - ] - } - } - }, - "required": [ - "product_name", - "product_version", - "release_date", - "author", - "reason" - ] - } - } - } - }, - "responses": { - "200": { - "description": "TEA Collection updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/tea_collection" - } - } - } - }, - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { "$ref": "#/components/responses/401-unauthorized" }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "tags": [ - "TEA Collection" - ], - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - }, - "delete": { - "description": "Delete a TEA Collection entry", - "operationId": "deleteTeaCollection", - "parameters": [ - { - "$ref": "#/components/parameters/tea_collection_identifier" - } - ], - "$ref": "#/components/operations/standard_delete", - "tags": [ - "TEA Collection" - ] - } - } - }, - "webhooks": {}, - "components": { - "schemas": { - "base_product_fields": { - "type": "object", - "properties": { - "product_name": { - "type": "string" - }, - "barcode": { - "type": "string", - "description": "Barcode" - }, - "sku": { - "type": "string", - "description": "Product SKU" - }, - "vendor_uuid": { - "$ref": "#/components/schemas/type_uuid", - "description": "Vendor UUID" - }, - "purl": { - "type": "string", - "description": "Package URL (PURL)" - } - } - }, - "base_versioned_product": { - "allOf": [ - { "$ref": "#/components/schemas/base_product_fields" }, - { - "type": "object", - "properties": { - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - } - } - } - ] - }, - "base_artifact_object": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "description": { - "type": "string" - }, - "media_type": { - "type": "string" - }, - "artifact_url": { - "type": "string", - "format": "uri" - }, - "artifact_size_in_bytes": { - "type": "integer", - "format": "int64" - }, - "artifact_checksum": { - "type": "string", - "description": "The checksum value" - }, - "artifact_checksum_type": { - "type": "string", - "description": "The algorithm used to generate the checksum", - "enum": [ - "SHA512", - "SHA384", - "SHA256", - "SHA224", - "SHA1", - "MD5", - "BLAKE2b-512", - "BLAKE2s-256", - "BLAKE3" - ], - "default": "SHA256" - } - } - }, - "tea_product": { - "allOf": [ - { "$ref": "#/components/schemas/base_product_fields" }, - { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "leaf_references": { - "type": "array", - "items": { - "$ref": "#/components/schemas/type_uuid" - }, - "description": "Array of UUIDs referencing TEA Leaf entries" - } - }, - "required": ["identifier", "product_name"] - } - ] - }, - "tea_leaf": { - "allOf": [ - { "$ref": "#/components/schemas/base_versioned_product" }, - { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "pre_release": { - "type": "boolean" - }, - "end_of_life": { - "type": "string", - "format": "date-time" - }, - "collection_references": { - "type": "array", - "items": { - "$ref": "#/components/schemas/type_uuid" - }, - "description": "Array of UUIDs referencing TEA Collection entries", - "default": [] - } - }, - "required": [ - "identifier", - "product_name", - "product_version", - "release_date", - "pre_release" - ] - } - ] - }, - "tea_collection": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "product_name": { - "type": "string" - }, - "product_version": { - "type": "string" - }, - "release_date": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "reason": { - "$ref": "#/components/schemas/type_collection_reason" - }, - "artifacts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/tea_collection_artifact" - }, - "default": [] - } - }, - "required": [ - "identifier", - "product_name", - "product_version", - "release_date", - "author", - "reason" - ] - }, - "tea_collection_artifact": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "name": { - "type": "string" - }, - "type": { - "$ref": "#/components/schemas/type_tea_collection_artifact_type" - }, - "author": { - "$ref": "#/components/schemas/type_author" - }, - "objects": { - "type": "array", - "items": { - "$ref": "#/components/schemas/tea_collection_artifact_object" - }, - "minItems": 1 - } - }, - "required": [ - "identifier", - "name", - "type", - "author", - "objects" - ] - }, - "tea_collection_artifact_object": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/type_uuid" - }, - "description": { - "type": "string" - }, - "media_type": { - "type": "string" - }, - "artifact_url": { - "type": "string", - "format": "uri" - }, - "artifact_size_in_bytes": { - "type": "integer", - "format": "int64" - }, - "artifact_checksum": { - "type": "string", - "description": "The checksum value" - }, - "artifact_checksum_type": { - "type": "string", - "description": "The algorithm used to generate the checksum", - "enum": [ - "SHA512", - "SHA384", - "SHA256", - "SHA224", - "SHA1", - "MD5", - "BLAKE2b-512", - "BLAKE2s-256", - "BLAKE3" - ], - "default": "SHA256" - }, - "signature_url": { - "type": "string", - "format": "uri" - } - }, - "required": [ - "identifier", - "description", - "media_type", - "artifact_url", - "artifact_size_in_bytes", - "artifact_checksum", - "artifact_checksum_type" - ] - }, - "type_author": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" - }, - "organization": { - "type": "string" - } - }, - "required": [ - "name", - "email", - "organization" - ] - }, - "type_collection_reason": { - "type": "string", - "description": "Event requiring this TEA Collection was published", - "enum": [ - "New Product Release", - "BOM Updated", - "Attestation Added", - "Attestation Updated" - ] - }, - "type_pagination_details": { - "type": "object", - "properties": { - "timestamp": { - "type": "string", - "format": "date-time", - "example": "2024-03-20T15:30:00Z" - }, - "page_start_index": { - "type": "number", - "format": "int64", - "default": 0 - }, - "page_size": { - "type": "number", - "format": "int64", - "default": 100 - }, - "total_results": { - "type": "number", - "format": "int64" - } - }, - "required": [ - "timestamp", - "page_start_index", - "page_size", - "total_results" - ] - }, - "type_tea_collection_artifact_type": { - "type": "string", - "title": "Type", - "description": "Specifies the type of external reference.", - "enum": [ - "vcs", - "issue-tracker", - "website", - "advisories", - "bom", - "mailing-list", - "social", - "chat", - "documentation", - "support", - "source-distribution", - "distribution", - "distribution-intake", - "license", - "build-meta", - "build-system", - "release-notes", - "security-contact", - "model-card", - "log", - "configuration", - "evidence", - "formulation", - "attestation", - "threat-model", - "adversary-model", - "risk-assessment", - "vulnerability-assertion", - "exploitability-statement", - "pentest-report", - "static-analysis-report", - "dynamic-analysis-report", - "runtime-analysis-report", - "component-analysis-report", - "maturity-report", - "certification-report", - "codified-infrastructure", - "quality-metrics", - "poam", - "electronic-signature", - "digital-signature", - "rfc-9116", - "other" - ], - "meta:enum": { - "vcs": "Version Control System", - "issue-tracker": "Issue or defect tracking system, or an Application Lifecycle Management (ALM) system", - "website": "Website", - "advisories": "Security advisories", - "bom": "Bill of Materials (SBOM, OBOM, HBOM, SaaSBOM, etc)", - "mailing-list": "Mailing list or discussion group", - "social": "Social media account", - "chat": "Real-time chat platform", - "documentation": "Documentation, guides, or how-to instructions", - "support": "Community or commercial support", - "source-distribution": { - "description": "The location where the source code distributable can be obtained. This is often an archive format such as zip or tgz. The source-distribution type complements use of the version control (vcs) type." - }, - "distribution": "Direct or repository download location", - "distribution-intake": "The location where a component was published to. This is often the same as \"distribution\" but may also include specialized publishing processes that act as an intermediary.", - "license": "The reference to the license file. If a license URL has been defined in the license node, it should also be defined as an external reference for completeness.", - "build-meta": "Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)", - "build-system": "Reference to an automated build system", - "release-notes": "Reference to release notes", - "security-contact": "Specifies a way to contact the maintainer, supplier, or provider in the event of a security incident. Common URIs include links to a disclosure procedure, a mailto (RFC-2368) that specifies an email address, a tel (RFC-3966) that specifies a phone number, or dns (RFC-4501) that specifies the records containing DNS Security TXT.", - "model-card": "A model card describes the intended uses of a machine learning model, potential limitations, biases, ethical considerations, training parameters, datasets used to train the model, performance metrics, and other relevant data useful for ML transparency.", - "log": "A record of events that occurred in a computer system or application, such as problems, errors, or information on current operations.", - "configuration": "Parameters or settings that may be used by other components or services.", - "evidence": "Information used to substantiate a claim.", - "formulation": "Describes how a component or service was manufactured or deployed.", - "attestation": "Human or machine-readable statements containing facts, evidence, or testimony.", - "threat-model": "An enumeration of identified weaknesses, threats, and countermeasures, dataflow diagram (DFD), attack tree, and other supporting documentation in human-readable or machine-readable format.", - "adversary-model": "The defined assumptions, goals, and capabilities of an adversary.", - "risk-assessment": "Identifies and analyzes the potential of future events that may negatively impact individuals, assets, and/or the environment. Risk assessments may also include judgments on the tolerability of each risk.", - "vulnerability-assertion": "A Vulnerability Disclosure Report (VDR) which asserts the known and previously unknown vulnerabilities that affect a component, service, or product including the analysis and findings describing the impact (or lack of impact) that the reported vulnerability has on a component, service, or product.", - "exploitability-statement": "A Vulnerability Exploitability eXchange (VEX) which asserts the known vulnerabilities that do not affect a product, product family, or organization, and optionally the ones that do. The VEX should include the analysis and findings describing the impact (or lack of impact) that the reported vulnerability has on the product, product family, or organization.", - "pentest-report": "Results from an authorized simulated cyberattack on a component or service, otherwise known as a penetration test.", - "static-analysis-report": "SARIF or proprietary machine or human-readable report for which static analysis has identified code quality, security, and other potential issues with the source code.", - "dynamic-analysis-report": "Dynamic analysis report that has identified issues such as vulnerabilities and misconfigurations.", - "runtime-analysis-report": "Report generated by analyzing the call stack of a running application.", - "component-analysis-report": "Report generated by Software Composition Analysis (SCA), container analysis, or other forms of component analysis.", - "maturity-report": "Report containing a formal assessment of an organization, business unit, or team against a maturity model.", - "certification-report": "Industry, regulatory, or other certification from an accredited (if applicable) certification body.", - "codified-infrastructure": "Code or configuration that defines and provisions virtualized infrastructure, commonly referred to as Infrastructure as Code (IaC).", - "quality-metrics": "Report or system in which quality metrics can be obtained.", - "poam": "Plans of Action and Milestones (POAM) complement an \"attestation\" external reference. POAM is defined by NIST as a \"document that identifies tasks needing to be accomplished. It details resources required to accomplish the elements of the plan, any milestones in meeting the tasks and scheduled completion dates for the milestones\".", - "electronic-signature": "An e-signature is commonly a scanned representation of a written signature or a stylized script of the person's name.", - "digital-signature": "A signature that leverages cryptography, typically public/private key pairs, which provides strong authenticity verification.", - "rfc-9116": "Document that complies with RFC-9116 (A File Format to Aid in Security Vulnerability Disclosure)", - "other": "Use this if no other types accurately describe the purpose of the external reference." - } - }, - "type_uuid": { - "type": "string", - "format": "uuid" - } - }, - "responses": { - "base_error": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - } - } - }, - "404-object-by-id-not-found": { - "description": "Object requested by identifier not found", - "content": { - "application/json": {} - } - }, - "401-unauthorized": { - "description": "Authentication required", - "content": { - "application/json": {} - } - } - }, - "parameters": { - "page-offset": { - "name": "page-offset", - "description": "Pagination offset", - "in": "query", - "required": false, - "schema": { - "type": "number", - "format": "int64", - "default": 0 - } - }, - "page-size": { - "name": "page-size", - "description": "Pagination offset", - "in": "query", - "required": false, - "schema": { - "type": "number", - "format": "int64", - "default": 100 - } - }, - "tei_urn": { - "name": "tei_urn", - "description": "Transparency Exchange Identifier (URN)", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - "tea_product_identifier": { - "name": "tea_product_identifier", - "description": "TEA Product Identifier", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - "product_version": { - "name": "product_version", - "description": "Product Version string", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - "tea_collection_identifier": { - "name": "tea_collection_identifier", - "description": "TEA Collection Identifier", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - "tea_leaf_identifier": { - "name": "tea_leaf_identifier", - "description": "TEA Leaf Identifier", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - "purl": { - "name": "purl", - "description": "Package URL (PURL)", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - }, - "barcode": { - "name": "barcode", - "description": "Barcode", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - }, - "sku": { - "name": "sku", - "description": "Product SKU", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - }, - "vendor_uuid": { - "name": "vendor_uuid", - "description": "Vendor UUID", - "in": "query", - "required": false, - "schema": { - "$ref": "#/components/schemas/type_uuid" - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" - }, - "basicAuth": { - "type": "http", - "scheme": "basic" - } - }, - "security_requirements": { - "standard_auth": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ] - }, - "responses": { - "standard_errors": { - "400": { - "description": "Invalid request body", - "content": { - "application/json": {} - } - }, - "401": { - "$ref": "#/components/responses/401-unauthorized" - }, - "404": { - "$ref": "#/components/responses/404-object-by-id-not-found" - } - }, - "standard_delete": { - "204": { - "description": "Resource successfully deleted" - } - } - }, - "parameters": { - "standard_pagination": { - "page_offset": { - "$ref": "#/components/parameters/page-offset" - }, - "page_size": { - "$ref": "#/components/parameters/page-size" - } - } - }, - "operations": { - "standard_delete": { - "responses": { - "$ref": "#/components/responses/standard_delete" - }, - "security": { - "$ref": "#/components/security_requirements/standard_auth" - } - } - } - }, - "security": [ - { - "bearerAuth": [] - }, - { - "basicAuth": [] - } - ], - "tags": [ - "TEA Collection", - "TEA Product", - "TEA Leaf" - ], - "externalDocs": { - "description": "Transparency Exchange API specification", - "url": "https://github.com/CycloneDX/transparency-exchange-api" - } -} \ No newline at end of file diff --git a/spec/publisher/openapi.yaml b/spec/publisher/openapi.yaml new file mode 100644 index 0000000..887f063 --- /dev/null +++ b/spec/publisher/openapi.yaml @@ -0,0 +1,3472 @@ +# GENERATED FILE - do not edit by hand. +# +# Built by spec/publisher/build.mjs from: +# spec/openapi.yaml (the consumption specification, version 0.4.0) +# spec/publisher/overlay.yaml (the publication operations) +# +# Regenerate with: node spec/publisher/build.mjs + +openapi: 3.1.1 +jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base +info: + title: Transparency Exchange API + summary: The OWASP Transparency Exchange API specification for consumers and publishers + description: |- + TBC + + This document is the consumption specification plus the publication + operations. Everything the two share, whether products, components, + releases, collections, artifacts, checksums or identifiers, has a single + definition, + taken from the consumption specification, so a publisher and a consumer + cannot hold different ideas of the same object. + + Generated by spec/publisher/build.mjs. Do not edit by hand: edit + spec/publisher/overlay.yaml, or the consumption specification, and rebuild. + contact: + name: TEA Working Group + email: tbc@somewhere.tld + url: https://github.com/CycloneDX/transparency-exchange-api + license: + name: Apache 2.0 + url: https://github.com/CycloneDX/transparency-exchange-api/blob/main/LICENSE + version: 0.4.0 +servers: + - url: http://localhost/tea/v1 + description: Local development +paths: + /product/{uuid}: + get: + description: Get a TEA Product by UUID + operationId: getTeaProductByUuid + parameters: + - name: uuid + in: path + required: true + description: UUID of the TEA product in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Product found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/product" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product + patch: + summary: Update a TEA Product + description: Update a product's mutable fields. Omitted fields are left unchanged. + operationId: updateTeaProduct + parameters: + - $ref: "#/components/parameters/object-uuid" + requestBody: + $ref: "#/components/requestBodies/write-product" + responses: + "200": + $ref: "#/components/responses/product-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Delete a TEA Product + description: | + Delete a product and everything beneath it. + + Deletion does not retract what consumers already hold. A product that + has been public SHOULD also be withdrawn through a CLE `withdrawn` + event, so a consumer who acted on it learns that it was retracted + rather than simply finding it gone. + operationId: deleteTeaProduct + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /product/{uuid}/releases: + get: + description: Get releases of the product + operationId: getReleasesByProductId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product-release" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-product-release" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product Release + /productRelease/{uuid}: + get: + description: Get a TEA Product Release + operationId: getTeaProductReleaseByUuid + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Product Release found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/productRelease" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product Release + patch: + summary: Update a TEA Product Release + operationId: updateTeaProductRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Update a product release's mutable fields. + requestBody: + $ref: "#/components/requestBodies/write-product-release" + responses: + "200": + $ref: "#/components/responses/product-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Delete a TEA Product Release + operationId: deleteTeaProductRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Delete a product release and the collection it holds. + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /productRelease/{uuid}/cle: + get: + description: Get the CLE (Common Lifecycle Enumeration) data for a TEA Product Release + operationId: getCleByProductReleaseId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: CLE data for the requested TEA Product Release found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/cle" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - CLE + /productReleases: + get: + description: Returns a list of TEA product releases. Note that multiple product releases may match. + operationId: queryTeaProductReleases + parameters: + - $ref: "#/components/parameters/id-type" + - $ref: "#/components/parameters/id-value" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product-release" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-product-release" + "400": + $ref: "#/components/responses/400-invalid-request" + tags: + - TEA Product Release + /product/{uuid}/cle: + get: + description: Get the CLE (Common Lifecycle Enumeration) data for a TEA Product + operationId: getCleByProductId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: CLE data for the requested TEA Product found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/cle" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - CLE + /products: + get: + description: Returns a list of TEA products. Note that multiple products may match. + operationId: queryTeaProducts + parameters: + - $ref: "#/components/parameters/id-type" + - $ref: "#/components/parameters/id-value" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-product" + "400": + $ref: "#/components/responses/400-invalid-request" + tags: + - TEA Product + /component/{uuid}: + get: + description: Get a TEA Component + operationId: getTeaComponentById + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Component found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/component" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component + patch: + summary: Update a TEA Component + description: Update a component's mutable fields. Omitted fields are left unchanged. + operationId: updateTeaComponent + parameters: + - $ref: "#/components/parameters/object-uuid" + requestBody: + $ref: "#/components/requestBodies/write-component" + responses: + "200": + $ref: "#/components/responses/component-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Delete a TEA Component + description: Delete a component and its releases. + operationId: deleteTeaComponent + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /component/{uuid}/releases: + get: + description: Get releases of the component + operationId: getReleasesByComponentId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-component-release" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-component-release" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component + /component/{uuid}/cle: + get: + description: Get the CLE (Common Lifecycle Enumeration) data for a TEA Component + operationId: getCleByComponentId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: CLE data for the requested TEA Component found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/cle" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - CLE + /components: + get: + description: Returns a list of TEA components. Note that multiple components may match. + operationId: queryTeaComponents + parameters: + - $ref: "#/components/parameters/id-type" + - $ref: "#/components/parameters/id-value" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-component" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-component" + "400": + $ref: "#/components/responses/400-invalid-request" + tags: + - TEA Component + /componentReleases: + get: + description: Returns a list of TEA component releases. Note that multiple component releases may match. + operationId: queryTeaComponentReleases + parameters: + - $ref: "#/components/parameters/id-type" + - $ref: "#/components/parameters/id-value" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-component" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-component-release" + "400": + $ref: "#/components/responses/400-invalid-request" + tags: + - TEA Component Release + /componentRelease/{uuid}: + get: + description: Get the TEA Component Release with its latest collection + operationId: getComponentReleaseById + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Component Release and its latest Collection found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/component-release-with-collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component Release + patch: + summary: Update a TEA Component Release + operationId: updateTeaComponentRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Update a component release's mutable fields. + requestBody: + $ref: "#/components/requestBodies/write-component-release" + responses: + "200": + $ref: "#/components/responses/component-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Delete a TEA Component Release + operationId: deleteTeaComponentRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Delete a component release and the collection it holds. + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /componentRelease/{uuid}/cle: + get: + description: Get the CLE (Common Lifecycle Enumeration) data for a TEA Component Release + operationId: getCleByComponentReleaseId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: CLE data for the requested TEA Component Release found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/cle" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - CLE + /componentRelease/{uuid}/collection/latest: + get: + description: Get the latest TEA Collection belonging to the TEA Component Release + operationId: getLatestCollection + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Collection found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component Release + /productRelease/{uuid}/collection/latest: + get: + description: Get the latest TEA Collection belonging to the TEA Product Release + operationId: getLatestCollectionForProductRelease + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Collection found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product Release + /componentRelease/{uuid}/collections: + get: + description: Get the TEA Collections belonging to the TEA Component Release + operationId: getCollectionsByReleaseId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Component Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-collection" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component Release + /productRelease/{uuid}/collections: + get: + description: Get the TEA Collections belonging to the TEA Product Release + operationId: getCollectionsByProductReleaseId + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-collection" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product Release + /productRelease/{uuid}/collection/{collectionVersion}: + get: + description: Get a specific Collection (by version) for a TEA Product Release by its UUID + operationId: getCollectionForProductRelease + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Product Release in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - name: collectionVersion + in: path + required: true + description: Version of TEA Collection + schema: + type: integer + responses: + "200": + description: Requested TEA Collection Version found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Product Release + /componentRelease/{uuid}/collection/{collectionVersion}: + get: + description: Get a specific Collection (by version) for a TEA Component Release by its UUID + operationId: getCollection + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Collection in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - name: collectionVersion + in: path + required: true + description: Version of TEA Collection + schema: + type: integer + responses: + "200": + description: Requested TEA Collection Version found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Component Release + /artifact/{uuid}/latest: + get: + description: Get metadata for latest revision of a specific TEA Artifact + operationId: getLatestArtifact + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Artifact in the TEA server + schema: + $ref: "#/components/schemas/uuid" + responses: + "200": + description: Requested TEA Artifact metadata found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/artifact" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Artifact + /artifact/{uuid}/{artifactVersion}: + get: + description: Get metadata for a specific revision of a specific TEA Artifact + operationId: getArtifactByVersion + parameters: + - name: uuid + in: path + required: true + description: UUID of TEA Artifact in the TEA server + schema: + $ref: "#/components/schemas/uuid" + - name: artifactVersion + in: path + required: true + description: Version of TEA Artifact + schema: + type: integer + responses: + "200": + description: Requested TEA Artifact metadata found and returned + content: + application/json: + schema: + $ref: "#/components/schemas/artifact" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Artifact + /discovery: + get: + description: Discovery endpoint which resolves TEI into product release UUID. + operationId: discoveryByTei + parameters: + - name: tei + in: query + required: true + description: >- + Transparency Exchange Identifier (TEI) for the product being discovered. Provide the TEI + as a URL-encoded string per RFC 3986, RFC 3987. + schema: + type: string + example: urn%3Atei%3Auuid%3Aproducts.example.com%3Ad4d9f54a-abcf-11ee-ac79-1a52914d44b + responses: + "200": + $ref: "#/components/responses/discovery-response" + "400": + $ref: "#/components/responses/400-invalid-request" + "404": + $ref: "#/components/responses/404-object-by-id-not-found" + tags: + - TEA Discovery + /product: + post: + summary: Create a TEA Product + description: | + Create a product and return the object the consumption API will serve, + including the UUID and identifiers the server assigned. + operationId: createTeaProduct + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-product" + responses: + "201": + $ref: "#/components/responses/product-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /component: + post: + summary: Create a TEA Component + operationId: createTeaComponent + description: Create a component and return the object the consumption API will serve. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-component" + responses: + "201": + $ref: "#/components/responses/component-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /productRelease: + post: + summary: Create a TEA Product Release + operationId: createTeaProductRelease + description: Create a release of a product. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-product-release" + responses: + "201": + $ref: "#/components/responses/product-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /componentRelease: + post: + summary: Create a TEA Component Release + operationId: createTeaComponentRelease + description: Create a release of a component. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-component-release" + responses: + "201": + $ref: "#/components/responses/component-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /productRelease/{uuid}/collection: + put: + summary: Publish a new collection version for a product release + operationId: publishTeaProductReleaseCollection + parameters: + - $ref: "#/components/parameters/object-uuid" + description: | + Publish the next version of this release's collection. + + The server assigns the version, incrementing from the current one. + `updateReason` is required: a collection whose contents change without + saying why is indistinguishable, to a consumer, from one that was + tampered with. + requestBody: + $ref: "#/components/requestBodies/write-collection" + responses: + "200": + $ref: "#/components/responses/collection-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /componentRelease/{uuid}/collection: + put: + summary: Publish a new collection version for a component release + operationId: publishTeaComponentReleaseCollection + parameters: + - $ref: "#/components/parameters/object-uuid" + description: | + Publish the next version of this release's collection. The server + assigns the version, and `updateReason` is required. + requestBody: + $ref: "#/components/requestBodies/write-collection" + responses: + "200": + $ref: "#/components/responses/collection-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /componentRelease/{uuid}/distribution: + post: + summary: Declare a distribution of a component release + operationId: createTeaDistribution + description: | + Declare one delivered form of this release: a file to download, or a + channel a user installs from. + + Idempotent on the `url`, or on the `description` where a channel has no + single file to fetch, such as `brew install`, `scoop install` or + `nix run`. A + pipeline that retries therefore updates the link rather than leaving a + consumer to choose between two identical ones. + + At least one of `url` and `description` is required. A distribution + with neither is a UUID: it gives a consumer nothing to follow and + nothing to recognise. + + Checksums are recorded verbatim. This server does not hold the bytes a + distribution points at, so it cannot verify them and does not claim to + have, which is why a publisher should copy the digests from the same + manifest its users verify against rather than recomputing them. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-distribution" + responses: + "201": + $ref: "#/components/responses/distribution-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /distribution/{uuid}: + delete: + summary: Withdraw a distribution + operationId: deleteTeaDistribution + description: | + Stop advertising this download. + + It does not unpublish whatever the URL pointed at, and it does not + reach anyone who already resolved it. Withdrawing a link is a statement + about what this catalogue advertises from now on, not a recall. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /artifact: + post: + summary: Create a TEA Artifact + operationId: createTeaArtifact + description: | + Register an artifact within a release's collection. + + This creates the entry and its formats; it does not carry the bytes. + Content goes up per format afterwards. Keeping the two apart matters + because an SBOM is routinely tens of megabytes, and a publisher who + must resend all of it to correct one metadata field will in practice + not correct the field. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-artifact" + responses: + "201": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /artifact/{uuid}: + patch: + summary: Update a TEA Artifact + operationId: updateTeaArtifact + description: | + Update an artifact's metadata. + + Stored bytes are immutable: a checksum a consumer has already recorded + must not begin describing different content. Replacing content means a + new format or a new artifact version, never an overwrite in place. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + requestBody: + $ref: "#/components/requestBodies/update-artifact" + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Delete a TEA Artifact + operationId: deleteTeaArtifact + description: Delete an artifact and any content this server holds for it. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /artifact/{uuid}/format/{formatIndex}/content: + put: + summary: Upload artifact content + operationId: uploadTeaArtifactContent + description: | + Upload the bytes of one artifact format. + + The body is the artifact itself in its own media type, rather than + base64 inside JSON, which would inflate it by a third for no benefit. + + A client SHOULD send `Content-Digest` (RFC 9530). Where it does, the + server MUST verify it against the received bytes and reject a mismatch. + That is what makes an upload safe to retry: a truncated transfer fails + loudly instead of publishing corrupt content under a checksum that says + otherwise. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + - $ref: "#/components/parameters/format-index" + - $ref: "#/components/parameters/content-digest" + requestBody: + required: true + description: The artifact bytes, in the media type declared by the format. + content: + application/octet-stream: + schema: + type: string + format: binary + application/vnd.cyclonedx+json: + schema: + type: string + format: binary + application/spdx+json: + schema: + type: string + format: binary + application/sarif+json: + schema: + type: string + format: binary + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "413": + $ref: "#/components/responses/publisher-payload-too-large" + "415": + $ref: "#/components/responses/publisher-unsupported-media-type" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /artifact/{uuid}/format/{formatIndex}/signature: + put: + summary: Attach a detached signature to an artifact format + operationId: uploadTeaArtifactSignature + description: | + Attach a detached signature, declaring the scheme it was produced with. + + The consumption API exposes a `signatureUrl` and nothing more, so a + consumer must infer the scheme from the bytes before it can verify + anything. The publisher knows, and recording it is what turns a + signature from something that exists into something that can be + checked. See signatures/signature.md. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + - $ref: "#/components/parameters/format-index" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/artifact-signature" + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "415": + $ref: "#/components/responses/publisher-unsupported-media-type" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /publicationTargets: + get: + summary: List registered publication targets + operationId: listTeaPublicationTargets + description: The remote servers this organisation may mirror objects to. + parameters: + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-publication-target" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "501": + $ref: "#/components/responses/publisher-mirroring-unsupported" + tags: + - TEA Publication Target + security: + - bearerAuth: [] + - basicAuth: [] + post: + summary: Register a publication target + operationId: createTeaPublicationTarget + description: | + Register a remote TEA server this organisation may mirror to. + + A server SHOULD verify the target before accepting it, confirming that + the root answers, advertises a compatible version and accepts the + credential, so that a target which was never going to work fails here, in front of + whoever configured it, rather than later inside an asynchronous mirror + nobody is watching. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-publication-target" + responses: + "201": + $ref: "#/components/responses/publication-target-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + "501": + $ref: "#/components/responses/publisher-mirroring-unsupported" + tags: + - TEA Publication Target + security: + - bearerAuth: [] + - basicAuth: [] + /publicationTargets/{uuid}: + get: + summary: Read a publication target + operationId: getTeaPublicationTarget + description: The target as registered. The credential is never returned. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "200": + $ref: "#/components/responses/publication-target-written" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication Target + security: + - bearerAuth: [] + - basicAuth: [] + delete: + summary: Deregister a publication target + operationId: deleteTeaPublicationTarget + description: | + Stop mirroring to this target and discard its credential. + + It does not recall the copies already sent. The target holds them under + its own policy, which is what mirroring means, so removing a target is + a statement about future copies only. + + A server MUST also remove the target from any `publishTo` naming it, + rather than leaving policies pointing at a target that no longer + exists. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication Target + security: + - bearerAuth: [] + - basicAuth: [] + /publications: + get: + summary: List the products this organisation has published + operationId: listTeaPublications + description: | + The caller's own products, each with the access policy actually in + force and the number of releases beneath it. + + Paginated on the same terms as the consumption listings, because a + catalogue large enough to be worth reconciling is large enough to need + it. + parameters: + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-publication" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /publications/{uuid}/releases: + get: + summary: List the releases published under a product + operationId: listTeaPublishedReleases + description: | + The releases of one of the caller's own products, each with the policy + in force, the current collection version and how many artifacts it + holds. + + The collection version is what makes this worth having separately from + the consumption listing: a release whose collection is still at version + 0 has been created and never populated, which is invisible to a + consumer and is exactly the state a publisher wants to find. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product-release" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-published-release" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + security: + - bearerAuth: [] + - basicAuth: [] + /accessPolicy/{uuid}: + get: + summary: Read the access policy in force for an object + operationId: getTeaAccessPolicy + description: | + The access policy actually in force, after inheritance. + + Reported as both what the object declares and what it effectively has, + because the difference between the two is exactly where accidental + disclosure hides. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "200": + $ref: "#/components/responses/access-policy-read" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Access Policy + security: + - bearerAuth: [] + - basicAuth: [] + put: + summary: Set the access policy for an object + operationId: setTeaAccessPolicy + description: | + Replace the object's own access policy. + + A server MUST reject a policy wider than the effective policy of the + object's parent, with `ACCESS_WIDENS_PARENT`. + + A change to `public` MUST carry `confirm=public`, because no later + request undoes it: whatever was fetched while it was public stays + fetched. Naming the mechanism rather than only asking for "a + confirmation" is deliberate: an unspecified requirement is one every + publisher satisfies differently, which is the failure this document + exists to avoid. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/confirm-public" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/access-policy" + responses: + "200": + $ref: "#/components/responses/access-policy-read" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Access Policy + security: + - bearerAuth: [] + - basicAuth: [] +components: + schemas: + date-time: + type: string + description: Timestamp + format: date-time + pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$ + example: "2024-03-20T15:30:00Z" + identifier: + type: object + description: An identifier with a specified type + properties: + idType: + description: Type of identifier, e.g. `TEI`, `PURL`, `CPE` + $ref: "#/components/schemas/identifier-type" + idValue: + description: Identifier value + type: string + identifier-type: + type: string + description: Enumeration of identifiers types + enum: + - CPE + - TEI + - PURL + - COMPLIANCE_DOCUMENT + compliance-document-type: + type: string + description: > + Well-known compliance document types. When idType is COMPLIANCE_DOCUMENT, the idValue SHOULD + be one of these values. + enum: + - SOC_2_TYPE_I + - SOC_2_TYPE_II + - SOC_3 + - ISO_27001 + - ISO_27017 + - ISO_27018 + - ISO_27701 + - ISO_42001 + - PCI_DSS + - HIPAA + - FedRAMP + - GDPR + - CSA_STAR + - NIST_800_53 + - NIST_800_171 + - CMMC + - HITRUST + - TISAX + - CYBER_ESSENTIALS + - CYBER_ESSENTIALS_PLUS + uuid: + type: string + description: A UUID + format: uuid + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ + product: + type: object + description: A TEA product + properties: + uuid: + description: A unique identifier for the TEA product + $ref: "#/components/schemas/uuid" + name: + type: string + description: Product name + identifiers: + type: array + description: | + List of identifiers for the product, like TEI, CPE, PURL or other identifiers + items: + $ref: "#/components/schemas/identifier" + required: + - uuid + - name + - identifiers + examples: + - uuid: 09e8c73b-ac45-4475-acac-33e6a7314e6d + name: Apache Log4j 2 + identifiers: + - idType: CPE + idValue: cpe:2.3:a:apache:log4j + - idType: PURL + idValue: pkg:maven/org.apache.logging.log4j/log4j-api + productRelease: + type: object + description: A specific release of a TEA product + properties: + uuid: + description: A unique identifier for the TEA Product Release + $ref: "#/components/schemas/uuid" + product: + description: UUID of the TEA Product this release belongs to + $ref: "#/components/schemas/uuid" + productName: + description: Name of the TEA Product this release belongs to + type: string + example: Apache Log4j 2 + version: + description: Version number of the product release + type: string + example: 2.24.3 + createdDate: + description: Timestamp when this Product Release was created in TEA (for sorting purposes) + $ref: "#/components/schemas/date-time" + releaseDate: + description: Timestamp of the product release + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: > + A flag indicating pre-release (or beta) status. + + May be disabled after the creation of the release object, but can't be enabled after + creation of an object. + identifiers: + type: array + description: List of identifiers for the product release + items: + $ref: "#/components/schemas/identifier" + components: + type: array + description: > + List of component references that compose this product release. A component reference + can optionally include + + the UUID of a specific component release to pin the exact version. + items: + $ref: "#/components/schemas/component-ref" + required: + - uuid + - version + - createdDate + - components + examples: + - uuid: 123e4567-e89b-12d3-a456-426614174000 + version: 2.24.3 + createdDate: 2025-04-01T15:43:00.000Z + releaseDate: 2025-04-01T15:43:00.000Z + identifiers: + - idType: TEI + idValue: tei:vendor:product@2.24.3 + components: + - uuid: 3910e0fd-aff4-48d6-b75f-8bf6b84687f0 + - uuid: b844c9bd-55d6-478c-af59-954a932b6ad3 + release: da89e38e-95e7-44ca-aa7d-f3b6b34c7fab + component: + type: object + description: A TEA component + properties: + uuid: + description: A unique identifier for the TEA component + $ref: "#/components/schemas/uuid" + name: + type: string + description: Component name + identifiers: + type: array + description: List of identifiers for the component + items: + $ref: "#/components/schemas/identifier" + required: + - uuid + - name + - identifiers + examples: + - uuid: 3910e0fd-aff4-48d6-b75f-8bf6b84687f0 + name: Apache Log4j API + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.logging.log4j/log4j-api + - uuid: b844c9bd-55d6-478c-af59-954a932b6ad3 + name: Apache Log4j Core + identifiers: + - idType: CPE + idValue: cpe:2.3:a:apache:log4j + - idType: PURL + idValue: pkg:maven/org.apache.logging.log4j/log4j-core + component-ref: + type: object + description: A reference to a TEA component or specific component release + properties: + uuid: + description: A unique identifier for the TEA component + $ref: "#/components/schemas/uuid" + release: + description: > + Optional UUID of a specific release included in the product in the case where the + product + + always include a specific release of a component. The product name should include a + version + + identifier in this case. + $ref: "#/components/schemas/uuid" + required: + - uuid + release: + type: object + description: A TEA Component Release + properties: + uuid: + description: A unique identifier for the TEA Component Release + $ref: "#/components/schemas/uuid" + component: + description: UUID of the TEA Component this release belongs to + $ref: "#/components/schemas/uuid" + componentName: + description: Name of the TEA Component this release belongs to + type: string + example: tomcat + version: + description: Version number + type: string + example: 1.2.3 + createdDate: + description: Timestamp when this Release was created in TEA (for sorting purposes) + $ref: "#/components/schemas/date-time" + releaseDate: + description: Timestamp of the release + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: > + A flag indicating pre-release (or beta) status. + + May be disabled after the creation of the release object, but can't be enabled after + creation of an object. + identifiers: + type: array + description: List of identifiers for the component + items: + $ref: "#/components/schemas/identifier" + distributions: + type: array + description: List of different formats of this component release + items: + $ref: "#/components/schemas/release-distribution" + required: + - uuid + - version + - createdDate + examples: + - uuid: 605d0ecb-1057-40e4-9abf-c400b10f0345 + version: 11.0.7 + createdDate: 2025-05-07T18:08:00.000Z + releaseDate: 2025-05-12T18:08:00.000Z + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.7 + distributions: + - distributionId: 6a0d58e1-4896-4f1e-83f7-5feb6c032537 + description: Core binary distribution, zip archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?type=zip + checksums: + - algType: SHA_256 + algValue: 9da736a1cdd27231e70187cbc67398d29ca0b714f885e7032da9f1fb247693c1 + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip.asc + - distributionId: dba01c13-dd96-4928-be72-9c87ffa8cab8 + description: Core binary distribution, tar.gz archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?type=tar.gz + checksums: + - algType: SHA_256 + algValue: 2fcece641c62ba1f28e1d7b257493151fc44f161fb391015ee6a95fa71632fb9 + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.tar.gz + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.tar.gz.asc + - distributionId: cfe068c2-fae7-43d0-97ec-5ea092454040 + description: Core binary distribution, Windows x64 zip archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?classifier=windows-x64&type=zip + checksums: + - algType: SHA_256 + algValue: 62a5c358d87a8ef21d7ec1b3b63c9bbb577453dda9c00cbb522b16cee6c23fc4 + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6-windows-x64.zip + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip.asc + - distributionId: de45ffaf-e4b5-47b5-be28-444a76df098e + description: Core binary distribution, Windows Service Installer (MSI) + checksums: + - algType: SHA_512 + algValue: >- + 1d3824e7643c8aba455ab0bd9e67b14a60f2aaa6aa7775116bce40eb0579e8ced162a4f828051d3b867e96ee2858ec5da0cc654e83a83ba30823cbea0df4ff96 + url: https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.7/bin/apache-tomcat-11.0.7.exe + signatureUrl: >- + https://downloads.apache.org/tomcat/tomcat-11/v11.0.7/bin/apache-tomcat-11.0.7.exe.asc + - uuid: 95f481df-f760-47f4-b2f2-f8b76d858450 + version: 11.0.0-M26 + createdDate: 2024-09-13T17:49:00.000Z + preRelease: true + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.0-M26 + release-distribution: + type: object + properties: + distributionId: + description: A unique identifier for the TEA Distribution object + $ref: "#/components/schemas/uuid" + description: + type: string + description: Free-text description of the distribution. + identifiers: + type: array + description: List of identifiers specific to this distribution. + items: + $ref: "#/components/schemas/identifier" + url: + type: string + description: Direct download URL for the distribution. + format: url + signatureUrl: + type: string + description: Direct download URL for the distribution's external signature. + format: url + checksums: + type: array + description: List of checksums for the distribution. + items: + $ref: "#/components/schemas/checksum" + required: + - distributionId + examples: + - distributionId: 6a0d58e1-4896-4f1e-83f7-5feb6c032537 + description: Core binary distribution, zip archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?type=zip + checksums: + - algType: SHA_256 + algValue: 9da736a1cdd27231e70187cbc67398d29ca0b714f885e7032da9f1fb247693c1 + url: https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip.asc + - distributionId: dba01c13-dd96-4928-be72-9c87ffa8cab8 + description: Core binary distribution, tar.gz archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?type=tar.gz + checksums: + - algType: SHA_256 + algValue: 2fcece641c62ba1f28e1d7b257493151fc44f161fb391015ee6a95fa71632fb9 + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.tar.gz + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.tar.gz.asc + - distributionId: cfe068c2-fae7-43d0-97ec-5ea092454040 + description: Core binary distribution, Windows x64 zip archive + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.6?classifier=windows-x64&type=zip + checksums: + - algType: SHA_256 + algValue: 62a5c358d87a8ef21d7ec1b3b63c9bbb577453dda9c00cbb522b16cee6c23fc4 + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6-windows-x64.zip + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.6.zip.asc + - distributionId: de45ffaf-e4b5-47b5-be28-444a76df098e + description: Core binary distribution, Windows Service Installer (MSI) + checksums: + - algType: SHA_512 + algValue: >- + 1d3824e7643c8aba455ab0bd9e67b14a60f2aaa6aa7775116bce40eb0579e8ced162a4f828051d3b867e96ee2858ec5da0cc654e83a83ba30823cbea0df4ff96 + url: https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.7/bin/apache-tomcat-11.0.7.exe + signatureUrl: https://downloads.apache.org/tomcat/tomcat-11/v11.0.7/bin/apache-tomcat-11.0.7.exe.asc + component-release-with-collection: + type: object + description: A TEA Component Release combined with its latest collection + properties: + release: + description: The TEA Component Release information + $ref: "#/components/schemas/release" + latestCollection: + description: The latest TEA Collection for this component release + $ref: "#/components/schemas/collection" + required: + - release + - latestCollection + examples: + - release: + uuid: 605d0ecb-1057-40e4-9abf-c400b10f0345 + version: 11.0.7 + createdDate: 2025-05-07T18:08:00.000Z + releaseDate: 2025-05-12T18:08:00.000Z + identifiers: + - idType: PURL + idValue: pkg:maven/org.apache.tomcat/tomcat@11.0.7 + latestCollection: + uuid: 605d0ecb-1057-40e4-9abf-c400b10f0345 + version: 2 + date: 2025-05-12T18:08:00.000Z + belongsTo: COMPONENT_RELEASE + updateReason: + type: INITIAL_RELEASE + comment: Initial collection for this release + artifacts: + - uuid: 1cb47b95-8bf8-3bad-a5a4-0d54d86e10ce + name: Build SBOM + type: BOM + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX SBOM (XML) + url: >- + https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/11.0.7/tomcat-11.0.7-cyclonedx.xml + checksums: + - algType: SHA-256 + algValue: 9da736a1cdd27231e70187cbc67398d29ca0b714f885e7032da9f1fb247693c1 + - uuid: dfa35519-9734-4259-bba1-3e825cf4be06 + name: Vulnerability Disclosure Report + type: VULNERABILITIES + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX VDR (XML) + url: https://tomcat.apache.org/cyclonedx/vdr.xml + checksums: + - algType: SHA-256 + algValue: 75b81020b3917cb682b1a7605ade431e062f7a4c01a412f0b87543b6e995ad2a + collection: + type: object + description: A collection of security-related documents + properties: + uuid: + description: > + UUID of the TEA Collection object. + + This matches the UUID of the associated TEA Component Release or TEA Product Release + object. + + When updating a collection, only the `version` is changed. + $ref: "#/components/schemas/uuid" + version: + type: integer + description: | + TEA Collection version, incremented each time its content changes. + Versions start with 1. + date: + description: The date when the TEA Collection version was created. + $ref: "#/components/schemas/date-time" + belongsTo: + description: Indicates whether this collection belongs to a Component Release or a Product Release + $ref: "#/components/schemas/collection-belongs-to-type" + updateReason: + description: Reason for the update/release of the TEA Collection object. + $ref: "#/components/schemas/collection-update-reason" + artifacts: + type: array + description: List of TEA Artifact objects. + items: + $ref: "#/components/schemas/artifact" + examples: + - uuid: 4c72fe22-9d83-4c2f-8eba-d6db484f32c8 + version: 10 + date: 2024-12-13T00:00:00.000Z + updateReason: + type: ARTIFACT_UPDATED + comment: VDR file updated + artifacts: + - uuid: 1cb47b95-8bf8-3bad-a5a4-0d54d86e10ce + name: Build SBOM + type: BOM + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX SBOM (XML) + url: >- + https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.24.3/log4j-core-2.24.3-cyclonedx.xml + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.24.3/log4j-core-2.24.3-cyclonedx.xml.asc + checksums: + - algType: MD5 + algValue: 2e1a525afc81b0a8ecff114b8b743de9 + - algType: SHA-1 + algValue: 5a7d4caef63c5c5ccdf07c39337323529eb5a770 + - uuid: dfa35519-9734-4259-bba1-3e825cf4be06 + version: 7 + name: Vulnerability Disclosure Report + type: VULNERABILITIES + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX VDR (XML) + url: https://logging.apache.org/cyclonedx/vdr.xml + checksums: + - algType: SHA-256 + algValue: 75b81020b3917cb682b1a7605ade431e062f7a4c01a412f0b87543b6e995ad2a + collection-update-reason: + type: object + description: Reason for the update to the TEA collection + properties: + type: + description: Type of update reason. + $ref: "#/components/schemas/collection-update-reason-type" + comment: + type: string + description: Free text description + collection-update-reason-type: + type: string + description: Type of TEA collection update + enum: + - INITIAL_RELEASE + - VEX_UPDATED + - ARTIFACT_UPDATED + - ARTIFACT_ADDED + - ARTIFACT_REMOVED + collection-belongs-to-type: + type: string + description: Indicates whether a collection belongs to a component release or a product release + enum: + - COMPONENT_RELEASE + - PRODUCT_RELEASE + artifact: + type: object + description: A security-related document + properties: + uuid: + description: >- + The UUID of the TEA Artifact object. Together with *version* uniquely identifies the TEA + Artifact. + $ref: "#/components/schemas/uuid" + version: + description: > + An integer with default value 1. + + Together with *uuid* uniquely identifies the TEA Artifact. + + This field can be used to designate successive, immutable revisions of an artefact + content (e.g. an updated VEX file). + type: integer + default: 1 + name: + type: string + description: Name of TEA Artifact + type: + description: Type of TEA Artifact + $ref: "#/components/schemas/artifact-type" + createdDate: + description: The date when the TEA Artifact revision was created. + $ref: "#/components/schemas/date-time" + distributionIds: + type: array + description: | + List of TEA Component Release distributions that this TEA Artifact applies to. + If absent or empty, the TEA Artifact applies to all distributions. + items: + $ref: "#/components/schemas/uuid" + description: > + The distribution IDs of the TEA component release distributions that this TEA Artifact + applies to. + formats: + type: array + description: | + List of objects with the same content, but in different formats. + The order of the list has no significance. + items: + $ref: "#/components/schemas/artifact-format" + required: + - uuid + - type + - formats + examples: + - uuid: 1cb47b95-8bf8-3bad-a5a4-0d54d86e10ce + name: Build SBOM + type: BOM + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX SBOM (XML) + url: >- + https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.24.3/log4j-core-2.24.3-cyclonedx.xml + signatureUrl: >- + https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.24.3/log4j-core-2.24.3-cyclonedx.xml.asc + checksums: + - algType: MD5 + algValue: 2e1a525afc81b0a8ecff114b8b743de9 + - algType: SHA-1 + algValue: 5a7d4caef63c5c5ccdf07c39337323529eb5a770 + - uuid: dfa35519-9734-4259-bba1-3e825cf4be06 + version: 7 + name: Vulnerability Disclosure Report + type: VULNERABILITIES + formats: + - mediaType: application/vnd.cyclonedx+xml + description: CycloneDX VDR (XML) + url: https://logging.apache.org/cyclonedx/vdr.xml + checksums: + - algType: SHA-256 + algValue: 75b81020b3917cb682b1a7605ade431e062f7a4c01a412f0b87543b6e995ad2a + artifact-type: + type: string + description: Specifies the type of external reference. + enum: + - ATTESTATION + - BOM + - BUILD_META + - CERTIFICATION + - FORMULATION + - LICENSE + - RELEASE_NOTES + - SECURITY_TXT + - THREAT_MODEL + - VULNERABILITIES + - OTHER + artifact-format: + type: object + description: A security-related document in a specific format + properties: + mediaType: + type: string + description: The Media Type of the document + description: + type: string + description: A free text describing the TEA Artifact + url: + type: string + description: Direct download URL for the TEA Artifact + format: url + signatureUrl: + type: string + description: Direct download URL for an external signature of the TEA Artifact + format: url + checksums: + type: array + description: List of checksums for the TEA Artifact + items: + $ref: "#/components/schemas/checksum" + checksum: + type: object + properties: + algType: + description: Checksum algorithm + $ref: "#/components/schemas/checksum-type" + algValue: + type: string + description: Checksum value + required: + - algType + - algValue + checksum-type: + type: string + description: Checksum algorithm + enum: + - MD5 + - SHA-1 + - SHA-256 + - SHA-384 + - SHA-512 + - SHA3-256 + - SHA3-384 + - SHA3-512 + - BLAKE2b-256 + - BLAKE2b-384 + - BLAKE2b-512 + - BLAKE3 + unknown-error-type: + type: string + description: Classification of TEA error response + enum: + - OBJECT_UNKNOWN + - OBJECT_NOT_SHAREABLE + error-response: + type: object + description: Error response + additionalProperties: false + properties: + error: + $ref: "#/components/schemas/unknown-error-type" + required: + - error + tea-server-info: + type: object + description: TEA server information including URL, versions, and optional priority + additionalProperties: false + properties: + rootUrl: + description: Root URL of the TEA server for this TEI without trailing slash + type: string + format: uri + example: https://api.teaexample.com + versions: + description: Supported TEA API versions at this server without v prefix + type: array + minItems: 1 + items: + type: string + example: + - 0.2.0-beta.2 + - 1.0.0 + priority: + description: Optional priority for this server (0.0 to 1.0, where 1.0 is highest priority) + type: number + format: float + minimum: 0 + maximum: 1 + example: 0.8 + required: + - rootUrl + - versions + discovery-info: + type: object + description: Discovery information for a TEI + additionalProperties: false + properties: + productReleaseUuid: + description: UUID of the resolved TEA Product Release + $ref: "#/components/schemas/uuid" + example: d4d9f54a-abcf-11ee-ac79-1a52914d44b + servers: + description: Array of TEA server information + type: array + minItems: 1 + items: + $ref: "#/components/schemas/tea-server-info" + required: + - productReleaseUuid + - servers + cle-event-type: + type: string + description: The type of CLE lifecycle event + enum: + - released + - endOfDevelopment + - endOfSupport + - endOfLife + - endOfDistribution + - endOfMarketing + - supersededBy + - componentRenamed + - withdrawn + cle-version-specifier: + type: object + description: A version specifier that can be either a single version or a version range + properties: + version: + type: string + description: A specific version string + range: + type: string + description: A version range in vers format (e.g. "vers:npm/>=1.0.0|<2.0.0") + cle-event: + type: object + description: A discrete lifecycle event from the CLE specification + properties: + id: + type: integer + description: A unique, auto-incrementing integer identifier for the event + type: + description: The type of lifecycle event + $ref: "#/components/schemas/cle-event-type" + effective: + type: string + format: date-time + description: ISO 8601 timestamp (UTC) when the event takes effect + published: + type: string + format: date-time + description: ISO 8601 timestamp (UTC) when the event was first published + version: + type: string + description: Version string (used by released event type) + versions: + type: array + description: List of version specifiers affected by this event + items: + $ref: "#/components/schemas/cle-version-specifier" + supportId: + type: string + description: Reference to a support policy ID defined in the definitions section + license: + type: string + description: License identifier (used by released event type) + supersededByVersion: + type: string + description: Version string that supersedes the affected versions (used by supersededBy event type) + identifiers: + type: array + description: New identifiers for the component (used by componentRenamed event type) + items: + $ref: "#/components/schemas/identifier" + eventId: + type: integer + description: ID of the event being withdrawn (used by withdrawn event type) + reason: + type: string + description: Human-readable explanation (used by withdrawn event type) + description: + type: string + description: Human-readable description of the event + references: + type: array + description: List of URLs to supporting documentation + items: + type: string + format: uri + required: + - id + - type + - effective + - published + examples: + - id: 1 + type: released + effective: "2024-01-01T00:00:00Z" + version: 1.0.0 + license: MIT + published: "2023-06-01T00:00:00Z" + - id: 3 + type: endOfSupport + effective: "2024-01-01T00:00:00Z" + versions: + - version: 1.0.0 + supportId: standard + published: "2023-06-01T00:00:00Z" + cle-support-definition: + type: object + description: A support policy definition from CLE + properties: + id: + type: string + description: Unique identifier for the support policy + description: + type: string + description: Human-readable description of the policy + url: + type: string + format: uri + description: URL to detailed documentation about this support policy + required: + - id + - description + examples: + - id: standard + description: Standard product support policy + url: https://example.com/support/standard + cle-definitions: + type: object + description: Container for reusable CLE policy definitions + properties: + support: + type: array + description: List of support policies + items: + $ref: "#/components/schemas/cle-support-definition" + cle: + type: object + description: > + Common Lifecycle Enumeration (CLE) object based on ECMA-428 TC54 TG3 CLE Specification + v1.0.0. + + Contains lifecycle events and optional reusable definitions for a component or product. + properties: + events: + type: array + description: | + Ordered array of CLE Event objects representing lifecycle events. + MUST be ordered by ID in descending order (newest events with highest IDs first). + items: + $ref: "#/components/schemas/cle-event" + definitions: + description: Container for reusable policy definitions referenced by events + $ref: "#/components/schemas/cle-definitions" + required: + - events + examples: + - events: + - id: 3 + type: endOfSupport + effective: "2025-06-01T00:00:00Z" + versions: + - range: vers:npm/>=1.0.0|<2.0.0 + supportId: standard + published: "2025-01-01T00:00:00Z" + - id: 2 + type: endOfDevelopment + effective: "2025-01-01T00:00:00Z" + versions: + - version: 1.0.0 + supportId: standard + published: "2024-06-01T00:00:00Z" + - id: 1 + type: released + effective: "2024-01-01T00:00:00Z" + version: 1.0.0 + license: Apache-2.0 + published: "2024-01-01T00:00:00Z" + definitions: + support: + - id: standard + description: Standard product support policy + url: https://example.com/support/standard + pagination-details: + type: object + properties: + hasNext: + type: boolean + description: | + A flag (to aid clients) to know whether there is a next page of results to fetch. + + `nextPageToken` will always be supplied, hence this hint is included to aid clients. + default: false + nextPageToken: + type: string + nullable: false + description: | + A token that can be used in a following request to retrieve the next page or results. + + It must always be supplied in responses. + required: + - hasNext + - nextPageToken + paginated-product-response: + description: A paginated response containing TEA Products + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/product" + required: + - results + paginated-product-release-response: + description: A paginated response containing TEA Product Releases + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/productRelease" + required: + - results + paginated-component-response: + description: A paginated response containing TEA Components + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/component" + required: + - results + paginated-component-release-response: + description: A paginated response containing TEA Component Releases + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/release" + required: + - results + paginated-collection-response: + description: A paginated response containing TEA Collections + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/collection" + required: + - results + publisher-error-type: + type: string + description: | + Classification of a publication error. + + Extends the consumption specification's `unknown-error-type` with the + failures only a writer can hit. The two consumption values are repeated + so a client can branch on one enumeration rather than two. + enum: + - OBJECT_UNKNOWN + - OBJECT_NOT_SHAREABLE + - INVALID_REQUEST + - UNAUTHORIZED + - FORBIDDEN + - DUPLICATE_OBJECT + - VERSION_CONFLICT + - ACCESS_WIDENS_PARENT + - UNSUPPORTED_MEDIA_TYPE + - PAYLOAD_TOO_LARGE + - CHECKSUM_MISMATCH + - SIGNATURE_INVALID + - MIRRORING_UNSUPPORTED + - UNKNOWN_PUBLICATION_TARGET + publisher-error-response: + type: object + description: | + A publication error. Same envelope as the consumption specification's + `error-response`, over the wider publication enumeration, with an + optional human-readable message and a pointer to the offending field. + + Publication is automated, and a release pipeline is usually the caller, + so a failure has to be actionable without a human reading prose. + additionalProperties: false + properties: + error: + $ref: "#/components/schemas/publisher-error-type" + message: + type: string + description: Human-readable explanation. Not a stable interface; branch on `error`. + field: + type: string + description: JSON Pointer to the offending member of the request body, where one applies. + required: + - error + access-policy: + type: object + description: | + Who may read an object through the consumption API. + + TEA describes how transparency data is fetched, not who is entitled to + fetch it. That is a reasonable boundary for a consumption API and an + impossible one for a publication API, where the same server holds + material that is deliberately public, material shared with named + counterparties under agreement, and material that is purely internal. + Absent this, every publisher invents an answer, incompatibly. + + Resolved along the chain from the object to the root: an artifact sits + under its collection, a collection under its release, a release under + its product. The policy in force is the NARROWEST declared anywhere on + that chain, not the nearest. + + The distinction is the whole guarantee. Under nearest-wins, an artifact + that had declared `public` before its product was set to `private` goes + on being public, because its own declaration is the nearest one and so + becomes the answer. `ACCESS_WIDENS_PARENT` alone does not prevent this: + it rejects a declaration that is too wide at the moment it is written, + and says nothing about a parent narrowed afterwards. A publisher + narrowing a product is entitled to expect that to mean something about + everything beneath it. + + Where more than one level declares `shared`, the entitlements are the + INTERSECTION of their `sharedWith` sets and the earliest expiry applies. + A grant made on a child cannot create an entitlement its parent + withheld. + + A server MUST NOT rewrite the declarations of descendants when an + ancestor narrows. Folding is reversible and rewriting is not: widening + a product back restores each descendant to its own declaration and no + further, which is what makes a temporary embargo a supported operation + rather than a decision that cannot be undone. + + A consumer denied by this policy is answered with the consumption + specification's existing `OBJECT_NOT_SHAREABLE`, so enforcement needs + no new consumer-side behaviour. + additionalProperties: false + properties: + visibility: + type: string + description: | + `private`: only the publishing organisation may read it. + + `shared`: readable by the publishing organisation and the + organisations named in `sharedWith`. Authentication is required and + the reader's identity decides the answer. + + `public`: readable without authentication. The only value that + makes an object part of the open transparency web, and irreversible + in practice: what has been fetched cannot be recalled. + enum: + - private + - shared + - public + default: private + sharedWith: + type: array + description: | + Organisations entitled to read this object when `visibility` is + `shared`. MUST be empty for any other visibility, so that a later + change to `private` cannot silently leave a grant standing. + items: + $ref: "#/components/schemas/share-grant" + publishTo: + type: array + description: | + Registered publication targets this object is mirrored to, by + UUID. Mirroring is a copy, not a reference: once an object reaches + another server, this server's policy no longer governs it, which is + why a target has to be registered deliberately rather than named + inline by URL. + + A server that does not mirror MUST reject a non-empty list with + `MIRRORING_UNSUPPORTED`. Accepting it and doing nothing is the one + unacceptable response, because the publisher would then believe a + copy exists somewhere it does not. + + Naming a target that is not registered is `UNKNOWN_PUBLICATION_TARGET`. + items: + $ref: "#/components/schemas/uuid" + required: + - visibility + share-grant: + type: object + description: An entitlement for one organisation to read one object. + additionalProperties: false + properties: + organizationUuid: + description: The consuming organisation's identifier on this server. + $ref: "#/components/schemas/uuid" + organizationName: + type: string + description: Display name when the grant was made. Advisory; the UUID is the identity. + grantedAt: + $ref: "#/components/schemas/date-time" + expiresAt: + description: | + When the grant lapses. A grant for the length of an evaluation or a + contract is the common case, and a server that cannot express an + expiry pushes publishers towards grants nobody ever revokes. + $ref: "#/components/schemas/date-time" + required: + - organizationUuid + publication-target: + type: object + description: | + A remote TEA server this publisher mirrors objects to, as this server + holds it. + + Registered as its own object rather than named inline in a policy for + two reasons. A credential is involved, and a credential repeated in + every policy is a credential in every audit log. And mirroring is a + copy the receiving server then governs, so which servers a publisher is + willing to hand objects to is a decision worth making once and + reviewing, not one made in passing while setting a visibility. + additionalProperties: false + properties: + uuid: + description: Identifier of this target on this server. + $ref: "#/components/schemas/uuid" + rootUrl: + type: string + format: uri + description: | + The remote server's TEA root, without a trailing slash. This is the + same value that server advertises as `rootUrl` in its own discovery + document. + domain: + type: string + description: | + The TEI domain-name component of the target, which is what a + consumer resolves. Derived from `rootUrl` and reported so a + publisher can see where a copy went. + description: + type: string + description: What this target is, for whoever reviews the list later. + credential: + type: string + writeOnly: true + description: | + Bearer credential this server presents when publishing to the + target. Write-only: a server MUST NOT return it, and MUST NOT + report whether one is held in any form that distinguishes one + credential from another. + createdAt: + $ref: "#/components/schemas/date-time" + required: + - uuid + - rootUrl + mirror-status: + type: object + description: | + The state of mirroring one object to one target. + + Reported rather than set: a publisher states where an object should go + and the server reports how far it got. A publisher that cannot see a + failed mirror has to discover it from the counterparty. + additionalProperties: false + properties: + target: + description: The publication target this state refers to. + $ref: "#/components/schemas/uuid" + domain: + type: string + description: The target's TEI domain, repeated so a reader need not resolve the UUID. + state: + type: string + description: | + State of the most recent attempt. + + `pending` means accepted locally and not yet copied. `published` + means the target acknowledged it. `failed` means the last attempt did not + succeed and `detail` says why; the server SHOULD retry, and MUST + NOT silently give up without leaving this state visible. + enum: + - pending + - published + - failed + lastAttemptAt: + $ref: "#/components/schemas/date-time" + detail: + type: string + description: Why the last attempt failed, when it did. + required: + - target + - state + artifact-signature: + type: object + description: | + A detached signature over an artifact format's bytes. + + signatures/signature.md calls for an indication of the hash algorithm, + an indicator of the certificate used, and the intermediate and signing + certificates. This carries them, plus the transparency-log entry where + the scheme has one. A signature that is itself publicly logged is far + harder to backdate. + additionalProperties: false + properties: + signatureType: + type: string + description: The scheme, so a consumer knows how to verify rather than having to guess. + enum: + - jws + - jsf + - cose + - pgp + - x509-cms + - sigstore-bundle + - ssh + url: + type: string + format: url + description: Direct download URL for the detached signature. + algorithm: + type: string + description: Hash algorithm the signature was computed over, e.g. SHA-256. + keyId: + type: string + description: Key identifier the signature was produced with, where the scheme has one. + certificateUrl: + type: string + format: url + description: Signing certificate, where verification needs one. + certificateChainUrl: + type: string + format: url + description: Intermediate certificates between the signing certificate and a trusted root. + transparencyLogUrl: + type: string + format: url + description: Entry in a signature transparency log, such as Rekor. + signedAt: + $ref: "#/components/schemas/date-time" + required: + - signatureType + - url + access-policy-status: + type: object + description: An object's declared access policy alongside the one actually enforced. + additionalProperties: false + properties: + uuid: + description: The object the policy applies to. + $ref: "#/components/schemas/uuid" + declared: + description: | + What this object sets for itself. Absent when it declares nothing + and relies entirely on inheritance. + $ref: "#/components/schemas/access-policy" + effective: + description: | + What is enforced: the narrowest policy declared between this object + and the root, with `shared` entitlements intersected. + $ref: "#/components/schemas/access-policy" + inheritedFrom: + description: | + The ancestor that constrained the answer, so a publisher can fix the + cause rather than the symptom. + + Present whenever an ancestor is what makes the effective policy + narrower than this object's own declaration, which includes the case + where the object declares something of its own and is overruled. An + ancestor that merely agrees is not the cause and is not reported. + $ref: "#/components/schemas/uuid" + mirrors: + type: array + description: | + How far mirroring has got, per target. Absent where the object is + mirrored nowhere, or where the server does not mirror at all. + items: + $ref: "#/components/schemas/mirror-status" + required: + - uuid + - effective + publication: + type: object + description: | + One product this organisation has published, as the consumption API + serves it, alongside the access policy in force for it. + + The product is carried whole rather than flattened so that a publisher + can compare it byte for byte against what `GET /product/{uuid}` + returns; a summary in a different shape would have to be trusted rather + than checked. + additionalProperties: false + properties: + product: + $ref: "#/components/schemas/product" + accessPolicy: + description: Declared and effective policy, so the gap between them is visible here too. + $ref: "#/components/schemas/access-policy-status" + releaseCount: + type: integer + minimum: 0 + description: How many releases exist beneath this product. + required: + - product + - accessPolicy + published-release: + type: object + description: One release this organisation has published, with what a consumer would find in it. + additionalProperties: false + properties: + release: + $ref: "#/components/schemas/productRelease" + accessPolicy: + $ref: "#/components/schemas/access-policy-status" + collectionVersion: + type: integer + minimum: 0 + description: | + Version of this release's current collection, or 0 where no + collection has been published yet, a release a consumer can + resolve and find nothing in. + artifactCount: + type: integer + minimum: 0 + description: How many artifacts the current collection holds. + required: + - release + - accessPolicy + paginated-publication-target-response: + description: A paginated response containing registered publication targets + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/publication-target" + required: + - results + paginated-publication-response: + description: A paginated response containing this organisation's published products + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/publication" + required: + - results + paginated-published-release-response: + description: A paginated response containing this organisation's published releases + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/published-release" + required: + - results + responses: + 204-common-delete: + description: Object deleted successfully + content: + application/json: {} + 400-invalid-request: + description: Request was Invalid + content: + application/json: {} + 401-unauthorized: + description: Authentication required + content: + application/json: {} + 404-object-by-id-not-found: + description: Object requested by identifier not found + content: + application/json: + schema: + $ref: "#/components/schemas/error-response" + discovery-response: + description: Discovery information for the requested TEI + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/discovery-info" + paginated-product: + description: A paginated response containing TEA Products + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-product-response" + paginated-product-release: + description: A paginated response containing TEA Product Releases + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-product-release-response" + paginated-component: + description: A paginated response containing TEA Components + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-component-response" + paginated-component-release: + description: A paginated response containing TEA Component Releases + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-component-release-response" + paginated-collection: + description: A paginated response containing TEA Collections + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-collection-response" + object-deleted: + description: | + The object was deleted and is no longer resolvable through the + consumption API. + publisher-bad-request: + description: The request body is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-unauthorized: + description: Authentication is required, or the credential was rejected. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-forbidden: + description: | + Authenticated, but not entitled to perform this operation on this + object. Distinct from 401 on purpose: a publisher debugging a pipeline + needs to know whether the credential was rejected or the permission + was. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-not-found: + description: No such object, or the caller may not see it. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-conflict: + description: | + The request conflicts with the object's current state: a create that + would duplicate an existing natural key, an update against a version + since superseded, or an access policy wider than the object's parent. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-mirroring-unsupported: + description: | + This server does not mirror to other TEA servers. Answered rather than + quietly ignoring the request, so a publisher is never left believing a + copy exists somewhere it does not. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-payload-too-large: + description: The uploaded content exceeds the size this server accepts. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-unsupported-media-type: + description: The supplied media type is not one this server accepts for the object. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + product-written: + description: The product as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/product" + component-written: + description: The component as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/component" + product-release-written: + description: The product release as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/productRelease" + component-release-written: + description: The component release as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/release" + collection-written: + description: The newly published collection version. + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + artifact-written: + description: The artifact as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/artifact" + distribution-written: + description: The distribution as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/release-distribution" + access-policy-read: + description: The access policy in force for the object. + content: + application/json: + schema: + $ref: "#/components/schemas/access-policy-status" + publication-target-written: + description: The publication target as registered, without its credential. + content: + application/json: + schema: + $ref: "#/components/schemas/publication-target" + paginated-publication-target: + description: A paginated response containing registered publication targets. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-publication-target-response" + paginated-publication: + description: A paginated response containing this organisation's published products. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-publication-response" + paginated-published-release: + description: A paginated response containing this organisation's published releases. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-published-release-response" + parameters: + page-size: + name: pageSize + description: The maximum number of results to return. + in: query + required: false + schema: + type: integer + format: int64 + minimum: 1 + maximum: 100 + default: 25 + page-token: + name: pageToken + description: | + An opaque token used to retrieve the next page of results. + This should be copied exactly from the `nextPageToken` field of a previous response. + in: query + required: false + schema: + type: string + sort-order: + name: sortOrder + description: The direction of the sort. + in: query + required: false + schema: + type: string + enum: + - asc + - desc + default: asc + sort-field-collection: + name: sortField + description: The field by which to sort the results. + in: query + required: false + schema: + type: string + enum: + - version + default: version + sort-field-component: + name: sortField + description: The field by which to sort the results. + in: query + required: false + schema: + type: string + enum: + - name + default: name + sort-field-component-release: + name: sortField + description: The field by which to sort the results. + in: query + required: false + schema: + type: string + enum: + - createdDate + - releaseDate + - version + default: createdDate + sort-field-product: + name: sortField + description: The field by which to sort the results. + in: query + required: false + schema: + type: string + enum: + - name + default: name + sort-field-product-release: + name: sortField + description: The field by which to sort the results. + in: query + required: false + schema: + type: string + enum: + - createdDate + - releaseDate + - version + default: createdDate + id-type: + name: idType + description: Type of identifier specified in the `idValue` parameter + in: query + schema: + $ref: "#/components/schemas/identifier-type" + id-value: + name: idValue + description: If present, only the objects with the given identifier value will be returned. + in: query + schema: + type: string + object-uuid: + name: uuid + in: path + required: true + description: UUID of the object. + schema: + $ref: "#/components/schemas/uuid" + artifact-uuid: + name: uuid + in: path + required: true + description: UUID of the TEA Artifact. + schema: + $ref: "#/components/schemas/uuid" + format-index: + name: formatIndex + in: path + required: true + description: | + Zero-based index of the format within the artifact's `formats` array. + Formats are addressed positionally because a media type is not unique + within an artifact: the same document is often published both + compressed and not. + schema: + type: integer + minimum: 0 + confirm-public: + name: confirm + in: query + required: false + description: | + Acknowledges an irreversible change. Required, with the value `public`, + on a request that sets `visibility` to `public`; ignored otherwise. + + A server MUST reject such a request without it, so that publishing to + the open web is something a caller states outright rather than + something a mistyped field does on its behalf. + schema: + type: string + enum: + - public + idempotency-key: + name: Idempotency-Key + in: header + required: false + description: | + A client-chosen key that makes a create safe to retry. + + Publication runs in release pipelines, and pipelines retry. Without + this, a timeout that actually succeeded produces a second object on the + next attempt, a duplicate discovered by a consumer rather than by the + publisher. A server supporting the key MUST return the original result + for a repeat of the same key rather than creating again. + schema: + type: string + maxLength: 255 + content-digest: + name: Content-Digest + in: header + required: false + description: | + Digest of the request body per RFC 9530, e.g. `sha-256=::`. + Where supplied, the server MUST verify it against the bytes received + and reject a mismatch rather than storing content that does not match + the checksum it will be published under. + schema: + type: string + securitySchemes: + bearerAuth: + type: http + scheme: bearer + basicAuth: + type: http + scheme: basic + requestBodies: + write-product: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + name: + type: string + description: Product name. + identifiers: + type: array + description: | + Identifiers for the product. A server assigns the TEI itself + because it names the server's own authority over the object, + so a + publisher supplying one would be asserting something only the + server can know. + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-component: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + name: + type: string + description: Component name. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-product-release: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + product: + description: UUID of the product this release belongs to. + $ref: "#/components/schemas/uuid" + version: + type: string + description: Version of the release. + releaseDate: + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: Whether this release is a pre-release. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + components: + type: array + description: | + The components this release is composed of, optionally + pinning a specific component release. + + Present because the consumption specification lists + `components` among `productRelease`'s required members: a + publisher with no way to state it can only ever produce + releases a server has to serve as an empty list, which is a + claim about the product rather than a gap in the record. + + Omitted means unchanged on update, and empty on create. + items: + $ref: "#/components/schemas/component-ref" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-component-release: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + component: + description: UUID of the component this release belongs to. + $ref: "#/components/schemas/uuid" + version: + type: string + description: Version of the release. + releaseDate: + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: Whether this release is a pre-release. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-publication-target: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + `uuid` and `domain` are absent by design: the server assigns the + first and derives the second from `rootUrl`, so the two cannot + disagree about which server a target actually is. + properties: + rootUrl: + type: string + format: uri + description: | + The remote server's TEA root, without a trailing slash. Must + be an absolute https URL, because a mirror carries a credential and + sending one over http would publish it to the network as well + as to the target. + description: + type: string + description: What this target is, for whoever reviews the list later. + credential: + type: string + writeOnly: true + description: | + Bearer credential to present when publishing to the target. + Never returned by any operation. + required: + - rootUrl + write-collection: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + updateReason: + description: Why this version was published. + $ref: "#/components/schemas/collection-update-reason" + accessPolicy: + $ref: "#/components/schemas/access-policy" + required: + - updateReason + write-distribution: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + `distributionId` is absent by design: the server assigns it, and + a publisher-supplied identifier would let one tenant claim + another's. It is derived from the release and the natural key + below, so re-publishing the same download is an update. + properties: + description: + type: string + description: | + What this channel or format is, in terms a human choosing how + to install would recognise. Required when there is no `url`, + and used as the natural key in that case. + url: + type: string + format: url + description: | + Direct download URL. Must be absolute and http(s): a relative + path would resolve against the consumer's own origin, and + other schemes ask a consumer to do something it did not + request. + signatureUrl: + type: string + format: url + description: Direct download URL for the detached signature. + identifiers: + type: array + description: | + Identifiers for this distribution specifically. Optional + because several real channels have no accepted purl type, + Homebrew and Scoop among them, and an identifier that names + a coordinate which does not resolve is worse than none, since + a consumer will follow it. + items: + $ref: "#/components/schemas/identifier" + checksums: + type: array + description: | + Recorded verbatim. This server does not hold the bytes and + cannot verify them, so these are the publisher's assertion, + not ours. + items: + $ref: "#/components/schemas/checksum" + anyOf: + - required: + - url + - required: + - description + write-artifact: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + collection: + description: | + UUID of the collection this artifact belongs to, which is the + UUID of its release. + $ref: "#/components/schemas/uuid" + name: + type: string + description: Human-readable name of the artifact. + type: + $ref: "#/components/schemas/artifact-type" + formats: + type: array + description: | + The representations this artifact is published in. A format + may carry a `url` when the publisher hosts the bytes itself; + otherwise they are uploaded to this server afterwards. + items: + $ref: "#/components/schemas/artifact-format" + distributionIds: + type: array + description: | + The distributions this artifact describes. Absent or empty + means it applies to all of them, which is what the + consumption specification says of the same field. + + It matters for exactly the case where an SBOM is not one + document: a Windows installer and a source tarball of the + same release have different contents, and an artifact that + cannot say which one it describes is attached to both + incorrectly. + items: + $ref: "#/components/schemas/uuid" + accessPolicy: + $ref: "#/components/schemas/access-policy" + required: + - collection + - name + - formats + update-artifact: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + Metadata only. Stored bytes are immutable: replacing content + means a new format or a new artifact, not an overwrite. + properties: + name: + type: string + type: + $ref: "#/components/schemas/artifact-type" + distributionIds: + type: array + description: | + Replaces the set of distributions this artifact describes. + An empty array means all of them. + items: + $ref: "#/components/schemas/uuid" + accessPolicy: + $ref: "#/components/schemas/access-policy" +security: + - bearerAuth: [] + - basicAuth: [] + - {} +tags: + - name: TEA Product + - name: TEA Product Release + - name: TEA Component + - name: TEA Component Release + - name: TEA Artifact + - name: TEA Discovery + - name: CLE + - name: TEA Publication + description: | + Operations that create, update and delete the objects the consumption API + serves. + - name: TEA Access Policy + description: | + Operations controlling who may read an object through the consumption + API: the publishing organisation alone, named counterparties, or anyone. + - name: TEA Publication Target + description: | + Registration of the remote TEA servers a publisher mirrors objects to. + Mirroring is a copy the receiving server then governs, so the set of + targets is configured deliberately rather than named in passing. +externalDocs: + description: Transparency Exchange API specification + url: https://github.com/CycloneDX/transparency-exchange-api diff --git a/spec/publisher/overlay.yaml b/spec/publisher/overlay.yaml new file mode 100644 index 0000000..5102fd0 --- /dev/null +++ b/spec/publisher/overlay.yaml @@ -0,0 +1,1747 @@ +# Publication operations, overlaid onto the consumption specification. +# +# Everything shared with the consumption API is referenced, never redefined. +# build.mjs fails the build if this file declares a path method, schema, +# parameter, response or request body that the consumption specification +# already owns, which is how the previous copy drifted. + +paths: + # ── Product ─────────────────────────────────────────────────────────────── + /product: + post: + summary: Create a TEA Product + description: | + Create a product and return the object the consumption API will serve, + including the UUID and identifiers the server assigned. + operationId: createTeaProduct + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-product" + responses: + "201": + $ref: "#/components/responses/product-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /product/{uuid}: + patch: + summary: Update a TEA Product + description: Update a product's mutable fields. Omitted fields are left unchanged. + operationId: updateTeaProduct + parameters: + - $ref: "#/components/parameters/object-uuid" + requestBody: + $ref: "#/components/requestBodies/write-product" + responses: + "200": + $ref: "#/components/responses/product-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + delete: + summary: Delete a TEA Product + description: | + Delete a product and everything beneath it. + + Deletion does not retract what consumers already hold. A product that + has been public SHOULD also be withdrawn through a CLE `withdrawn` + event, so a consumer who acted on it learns that it was retracted + rather than simply finding it gone. + operationId: deleteTeaProduct + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Component ───────────────────────────────────────────────────────────── + /component: + post: + summary: Create a TEA Component + operationId: createTeaComponent + description: Create a component and return the object the consumption API will serve. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-component" + responses: + "201": + $ref: "#/components/responses/component-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /component/{uuid}: + patch: + summary: Update a TEA Component + description: Update a component's mutable fields. Omitted fields are left unchanged. + operationId: updateTeaComponent + parameters: + - $ref: "#/components/parameters/object-uuid" + requestBody: + $ref: "#/components/requestBodies/write-component" + responses: + "200": + $ref: "#/components/responses/component-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + delete: + summary: Delete a TEA Component + description: Delete a component and its releases. + operationId: deleteTeaComponent + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Releases ────────────────────────────────────────────────────────────── + # Split to match the consumption API, which has distinguished product + # releases from component releases since 0.1.0. A single /release could not + # say which of the two it was creating. + /productRelease: + post: + summary: Create a TEA Product Release + operationId: createTeaProductRelease + description: Create a release of a product. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-product-release" + responses: + "201": + $ref: "#/components/responses/product-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /productRelease/{uuid}: + patch: + summary: Update a TEA Product Release + operationId: updateTeaProductRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Update a product release's mutable fields. + requestBody: + $ref: "#/components/requestBodies/write-product-release" + responses: + "200": + $ref: "#/components/responses/product-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + delete: + summary: Delete a TEA Product Release + operationId: deleteTeaProductRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Delete a product release and the collection it holds. + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + /componentRelease: + post: + summary: Create a TEA Component Release + operationId: createTeaComponentRelease + description: Create a release of a component. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-component-release" + responses: + "201": + $ref: "#/components/responses/component-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /componentRelease/{uuid}: + patch: + summary: Update a TEA Component Release + operationId: updateTeaComponentRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Update a component release's mutable fields. + requestBody: + $ref: "#/components/requestBodies/write-component-release" + responses: + "200": + $ref: "#/components/responses/component-release-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + delete: + summary: Delete a TEA Component Release + operationId: deleteTeaComponentRelease + parameters: + - $ref: "#/components/parameters/object-uuid" + description: Delete a component release and the collection it holds. + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Collections ─────────────────────────────────────────────────────────── + # A collection is not an independent object: the consumption specification + # states its UUID matches the release it belongs to, and that an update only + # changes the version. Publishing one is therefore addressed through its + # release, and is a PUT rather than a POST: there is one current collection + # per release, and this replaces it with the next version. + /productRelease/{uuid}/collection: + put: + summary: Publish a new collection version for a product release + operationId: publishTeaProductReleaseCollection + parameters: + - $ref: "#/components/parameters/object-uuid" + description: | + Publish the next version of this release's collection. + + The server assigns the version, incrementing from the current one. + `updateReason` is required: a collection whose contents change without + saying why is indistinguishable, to a consumer, from one that was + tampered with. + requestBody: + $ref: "#/components/requestBodies/write-collection" + responses: + "200": + $ref: "#/components/responses/collection-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + /componentRelease/{uuid}/collection: + put: + summary: Publish a new collection version for a component release + operationId: publishTeaComponentReleaseCollection + parameters: + - $ref: "#/components/parameters/object-uuid" + description: | + Publish the next version of this release's collection. The server + assigns the version, and `updateReason` is required. + requestBody: + $ref: "#/components/requestBodies/write-collection" + responses: + "200": + $ref: "#/components/responses/collection-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Distributions ───────────────────────────────────────────────────────── + # + # A collection says what evidence exists about a release. A distribution says + # how the release is obtained. Publishing the first without the second leaves + # a consumer that resolved a TEI holding an SBOM and no download link. + # + # Attached to a component release because that is where the consumption + # schema defines them: `release.distributions` exists, `productRelease` has no + # such field. A publisher wanting download links therefore decomposes its + # product into at least one component, the model the consumption + # specification already assumes, not an extra requirement of this overlay. + /componentRelease/{uuid}/distribution: + post: + summary: Declare a distribution of a component release + operationId: createTeaDistribution + description: | + Declare one delivered form of this release: a file to download, or a + channel a user installs from. + + Idempotent on the `url`, or on the `description` where a channel has no + single file to fetch, such as `brew install`, `scoop install` or + `nix run`. A + pipeline that retries therefore updates the link rather than leaving a + consumer to choose between two identical ones. + + At least one of `url` and `description` is required. A distribution + with neither is a UUID: it gives a consumer nothing to follow and + nothing to recognise. + + Checksums are recorded verbatim. This server does not hold the bytes a + distribution points at, so it cannot verify them and does not claim to + have, which is why a publisher should copy the digests from the same + manifest its users verify against rather than recomputing them. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-distribution" + responses: + "201": + $ref: "#/components/responses/distribution-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /distribution/{uuid}: + delete: + summary: Withdraw a distribution + operationId: deleteTeaDistribution + description: | + Stop advertising this download. + + It does not unpublish whatever the URL pointed at, and it does not + reach anyone who already resolved it. Withdrawing a link is a statement + about what this catalogue advertises from now on, not a recall. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Artifacts ───────────────────────────────────────────────────────────── + /artifact: + post: + summary: Create a TEA Artifact + operationId: createTeaArtifact + description: | + Register an artifact within a release's collection. + + This creates the entry and its formats; it does not carry the bytes. + Content goes up per format afterwards. Keeping the two apart matters + because an SBOM is routinely tens of megabytes, and a publisher who + must resend all of it to correct one metadata field will in practice + not correct the field. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-artifact" + responses: + "201": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Publication + /artifact/{uuid}: + patch: + summary: Update a TEA Artifact + operationId: updateTeaArtifact + description: | + Update an artifact's metadata. + + Stored bytes are immutable: a checksum a consumer has already recorded + must not begin describing different content. Replacing content means a + new format or a new artifact version, never an overwrite in place. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + requestBody: + $ref: "#/components/requestBodies/update-artifact" + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + delete: + summary: Delete a TEA Artifact + operationId: deleteTeaArtifact + description: Delete an artifact and any content this server holds for it. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + /artifact/{uuid}/format/{formatIndex}/content: + put: + summary: Upload artifact content + operationId: uploadTeaArtifactContent + description: | + Upload the bytes of one artifact format. + + The body is the artifact itself in its own media type, rather than + base64 inside JSON, which would inflate it by a third for no benefit. + + A client SHOULD send `Content-Digest` (RFC 9530). Where it does, the + server MUST verify it against the received bytes and reject a mismatch. + That is what makes an upload safe to retry: a truncated transfer fails + loudly instead of publishing corrupt content under a checksum that says + otherwise. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + - $ref: "#/components/parameters/format-index" + - $ref: "#/components/parameters/content-digest" + requestBody: + required: true + description: The artifact bytes, in the media type declared by the format. + content: + application/octet-stream: + schema: + type: string + format: binary + application/vnd.cyclonedx+json: + schema: + type: string + format: binary + application/spdx+json: + schema: + type: string + format: binary + application/sarif+json: + schema: + type: string + format: binary + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "413": + $ref: "#/components/responses/publisher-payload-too-large" + "415": + $ref: "#/components/responses/publisher-unsupported-media-type" + tags: + - TEA Publication + /artifact/{uuid}/format/{formatIndex}/signature: + put: + summary: Attach a detached signature to an artifact format + operationId: uploadTeaArtifactSignature + description: | + Attach a detached signature, declaring the scheme it was produced with. + + The consumption API exposes a `signatureUrl` and nothing more, so a + consumer must infer the scheme from the bytes before it can verify + anything. The publisher knows, and recording it is what turns a + signature from something that exists into something that can be + checked. See signatures/signature.md. + parameters: + - $ref: "#/components/parameters/artifact-uuid" + - $ref: "#/components/parameters/format-index" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/artifact-signature" + responses: + "200": + $ref: "#/components/responses/artifact-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "415": + $ref: "#/components/responses/publisher-unsupported-media-type" + tags: + - TEA Publication + + # ── Publication targets ─────────────────────────────────────────────────── + # + # Where `publishTo` sends a copy. Registration is separate from use because a + # credential is involved and because handing an object to another server is a + # decision that outlives the object: once a copy lands there, this server's + # access policy no longer governs it. + # + # Mirroring is asynchronous and MUST NOT block or fail the local write. A + # remote outage is the target's problem; refusing to record a publisher's own + # release because a mirror is unreachable would make every target a single + # point of failure for publication itself. The state is reported on the + # object's access policy instead, where a publisher can find it. + # + # Mirroring is one hop. A server MUST NOT onward-mirror an object it received + # as a copy, or two servers configured towards each other would exchange the + # same object indefinitely. + /publicationTargets: + get: + summary: List registered publication targets + operationId: listTeaPublicationTargets + description: The remote servers this organisation may mirror objects to. + parameters: + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-publication-target" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "501": + $ref: "#/components/responses/publisher-mirroring-unsupported" + tags: + - TEA Publication Target + post: + summary: Register a publication target + operationId: createTeaPublicationTarget + description: | + Register a remote TEA server this organisation may mirror to. + + A server SHOULD verify the target before accepting it, confirming that + the root answers, advertises a compatible version and accepts the + credential, so that a target which was never going to work fails here, in front of + whoever configured it, rather than later inside an asynchronous mirror + nobody is watching. + parameters: + - $ref: "#/components/parameters/idempotency-key" + requestBody: + $ref: "#/components/requestBodies/write-publication-target" + responses: + "201": + $ref: "#/components/responses/publication-target-written" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "409": + $ref: "#/components/responses/publisher-conflict" + "501": + $ref: "#/components/responses/publisher-mirroring-unsupported" + tags: + - TEA Publication Target + /publicationTargets/{uuid}: + get: + summary: Read a publication target + operationId: getTeaPublicationTarget + description: The target as registered. The credential is never returned. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "200": + $ref: "#/components/responses/publication-target-written" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication Target + delete: + summary: Deregister a publication target + operationId: deleteTeaPublicationTarget + description: | + Stop mirroring to this target and discard its credential. + + It does not recall the copies already sent. The target holds them under + its own policy, which is what mirroring means, so removing a target is + a statement about future copies only. + + A server MUST also remove the target from any `publishTo` naming it, + rather than leaving policies pointing at a target that no longer + exists. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "204": + $ref: "#/components/responses/object-deleted" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication Target + + # ── Publisher read surface ──────────────────────────────────────────────── + # + # A publisher cannot reconcile its own state through the consumption API, + # because that API answers what a *reader* is entitled to see. The one thing + # a publisher most needs to check, whether something private is in fact + # private, is precisely what a consumption response cannot tell it, since an + # object correctly withheld and an object that was never created look + # identical from outside. + # + # So these two operations report the objects the caller published together + # with the policy in force for each. They are scoped to the caller's own + # organisation and to no other; there is no cross-publisher listing here, + # deliberately. + /publications: + get: + summary: List the products this organisation has published + operationId: listTeaPublications + description: | + The caller's own products, each with the access policy actually in + force and the number of releases beneath it. + + Paginated on the same terms as the consumption listings, because a + catalogue large enough to be worth reconciling is large enough to need + it. + parameters: + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-publication" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + tags: + - TEA Publication + /publications/{uuid}/releases: + get: + summary: List the releases published under a product + operationId: listTeaPublishedReleases + description: | + The releases of one of the caller's own products, each with the policy + in force, the current collection version and how many artifacts it + holds. + + The collection version is what makes this worth having separately from + the consumption listing: a release whose collection is still at version + 0 has been created and never populated, which is invisible to a + consumer and is exactly the state a publisher wants to find. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/page-size" + - $ref: "#/components/parameters/page-token" + - $ref: "#/components/parameters/sort-field-product-release" + - $ref: "#/components/parameters/sort-order" + responses: + "200": + $ref: "#/components/responses/paginated-published-release" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Publication + + # ── Access policy ───────────────────────────────────────────────────────── + # Named "access policy" rather than "distribution" because the consumption + # specification already uses `release-distribution` for something else + # entirely: a downloadable build with its own URL and checksums. Reusing the + # word for access control in a combined document would be actively + # misleading. + /accessPolicy/{uuid}: + get: + summary: Read the access policy in force for an object + operationId: getTeaAccessPolicy + description: | + The access policy actually in force, after inheritance. + + Reported as both what the object declares and what it effectively has, + because the difference between the two is exactly where accidental + disclosure hides. + parameters: + - $ref: "#/components/parameters/object-uuid" + responses: + "200": + $ref: "#/components/responses/access-policy-read" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + tags: + - TEA Access Policy + put: + summary: Set the access policy for an object + operationId: setTeaAccessPolicy + description: | + Replace the object's own access policy. + + A server MUST reject a policy wider than the effective policy of the + object's parent, with `ACCESS_WIDENS_PARENT`. + + A change to `public` MUST carry `confirm=public`, because no later + request undoes it: whatever was fetched while it was public stays + fetched. Naming the mechanism rather than only asking for "a + confirmation" is deliberate: an unspecified requirement is one every + publisher satisfies differently, which is the failure this document + exists to avoid. + parameters: + - $ref: "#/components/parameters/object-uuid" + - $ref: "#/components/parameters/confirm-public" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/access-policy" + responses: + "200": + $ref: "#/components/responses/access-policy-read" + "400": + $ref: "#/components/responses/publisher-bad-request" + "401": + $ref: "#/components/responses/publisher-unauthorized" + "403": + $ref: "#/components/responses/publisher-forbidden" + "404": + $ref: "#/components/responses/publisher-not-found" + "409": + $ref: "#/components/responses/publisher-conflict" + tags: + - TEA Access Policy + +components: + schemas: + publisher-error-type: + type: string + description: | + Classification of a publication error. + + Extends the consumption specification's `unknown-error-type` with the + failures only a writer can hit. The two consumption values are repeated + so a client can branch on one enumeration rather than two. + enum: + - OBJECT_UNKNOWN + - OBJECT_NOT_SHAREABLE + - INVALID_REQUEST + - UNAUTHORIZED + - FORBIDDEN + - DUPLICATE_OBJECT + - VERSION_CONFLICT + - ACCESS_WIDENS_PARENT + - UNSUPPORTED_MEDIA_TYPE + - PAYLOAD_TOO_LARGE + - CHECKSUM_MISMATCH + - SIGNATURE_INVALID + - MIRRORING_UNSUPPORTED + - UNKNOWN_PUBLICATION_TARGET + + publisher-error-response: + type: object + description: | + A publication error. Same envelope as the consumption specification's + `error-response`, over the wider publication enumeration, with an + optional human-readable message and a pointer to the offending field. + + Publication is automated, and a release pipeline is usually the caller, + so a failure has to be actionable without a human reading prose. + additionalProperties: false + properties: + error: + $ref: "#/components/schemas/publisher-error-type" + message: + type: string + description: Human-readable explanation. Not a stable interface; branch on `error`. + field: + type: string + description: JSON Pointer to the offending member of the request body, where one applies. + required: + - error + + access-policy: + type: object + description: | + Who may read an object through the consumption API. + + TEA describes how transparency data is fetched, not who is entitled to + fetch it. That is a reasonable boundary for a consumption API and an + impossible one for a publication API, where the same server holds + material that is deliberately public, material shared with named + counterparties under agreement, and material that is purely internal. + Absent this, every publisher invents an answer, incompatibly. + + Resolved along the chain from the object to the root: an artifact sits + under its collection, a collection under its release, a release under + its product. The policy in force is the NARROWEST declared anywhere on + that chain, not the nearest. + + The distinction is the whole guarantee. Under nearest-wins, an artifact + that had declared `public` before its product was set to `private` goes + on being public, because its own declaration is the nearest one and so + becomes the answer. `ACCESS_WIDENS_PARENT` alone does not prevent this: + it rejects a declaration that is too wide at the moment it is written, + and says nothing about a parent narrowed afterwards. A publisher + narrowing a product is entitled to expect that to mean something about + everything beneath it. + + Where more than one level declares `shared`, the entitlements are the + INTERSECTION of their `sharedWith` sets and the earliest expiry applies. + A grant made on a child cannot create an entitlement its parent + withheld. + + A server MUST NOT rewrite the declarations of descendants when an + ancestor narrows. Folding is reversible and rewriting is not: widening + a product back restores each descendant to its own declaration and no + further, which is what makes a temporary embargo a supported operation + rather than a decision that cannot be undone. + + A consumer denied by this policy is answered with the consumption + specification's existing `OBJECT_NOT_SHAREABLE`, so enforcement needs + no new consumer-side behaviour. + additionalProperties: false + properties: + visibility: + type: string + description: | + `private`: only the publishing organisation may read it. + + `shared`: readable by the publishing organisation and the + organisations named in `sharedWith`. Authentication is required and + the reader's identity decides the answer. + + `public`: readable without authentication. The only value that + makes an object part of the open transparency web, and irreversible + in practice: what has been fetched cannot be recalled. + enum: + - private + - shared + - public + default: private + sharedWith: + type: array + description: | + Organisations entitled to read this object when `visibility` is + `shared`. MUST be empty for any other visibility, so that a later + change to `private` cannot silently leave a grant standing. + items: + $ref: "#/components/schemas/share-grant" + publishTo: + type: array + description: | + Registered publication targets this object is mirrored to, by + UUID. Mirroring is a copy, not a reference: once an object reaches + another server, this server's policy no longer governs it, which is + why a target has to be registered deliberately rather than named + inline by URL. + + A server that does not mirror MUST reject a non-empty list with + `MIRRORING_UNSUPPORTED`. Accepting it and doing nothing is the one + unacceptable response, because the publisher would then believe a + copy exists somewhere it does not. + + Naming a target that is not registered is `UNKNOWN_PUBLICATION_TARGET`. + items: + $ref: "#/components/schemas/uuid" + required: + - visibility + + share-grant: + type: object + description: An entitlement for one organisation to read one object. + additionalProperties: false + properties: + organizationUuid: + description: The consuming organisation's identifier on this server. + $ref: "#/components/schemas/uuid" + organizationName: + type: string + description: Display name when the grant was made. Advisory; the UUID is the identity. + grantedAt: + $ref: "#/components/schemas/date-time" + expiresAt: + description: | + When the grant lapses. A grant for the length of an evaluation or a + contract is the common case, and a server that cannot express an + expiry pushes publishers towards grants nobody ever revokes. + $ref: "#/components/schemas/date-time" + required: + - organizationUuid + + publication-target: + type: object + description: | + A remote TEA server this publisher mirrors objects to, as this server + holds it. + + Registered as its own object rather than named inline in a policy for + two reasons. A credential is involved, and a credential repeated in + every policy is a credential in every audit log. And mirroring is a + copy the receiving server then governs, so which servers a publisher is + willing to hand objects to is a decision worth making once and + reviewing, not one made in passing while setting a visibility. + additionalProperties: false + properties: + uuid: + description: Identifier of this target on this server. + $ref: "#/components/schemas/uuid" + rootUrl: + type: string + format: uri + description: | + The remote server's TEA root, without a trailing slash. This is the + same value that server advertises as `rootUrl` in its own discovery + document. + domain: + type: string + description: | + The TEI domain-name component of the target, which is what a + consumer resolves. Derived from `rootUrl` and reported so a + publisher can see where a copy went. + description: + type: string + description: What this target is, for whoever reviews the list later. + credential: + type: string + writeOnly: true + description: | + Bearer credential this server presents when publishing to the + target. Write-only: a server MUST NOT return it, and MUST NOT + report whether one is held in any form that distinguishes one + credential from another. + createdAt: + $ref: "#/components/schemas/date-time" + required: + - uuid + - rootUrl + + mirror-status: + type: object + description: | + The state of mirroring one object to one target. + + Reported rather than set: a publisher states where an object should go + and the server reports how far it got. A publisher that cannot see a + failed mirror has to discover it from the counterparty. + additionalProperties: false + properties: + target: + description: The publication target this state refers to. + $ref: "#/components/schemas/uuid" + domain: + type: string + description: The target's TEI domain, repeated so a reader need not resolve the UUID. + state: + type: string + description: | + State of the most recent attempt. + + `pending` means accepted locally and not yet copied. `published` + means the target acknowledged it. `failed` means the last attempt did not + succeed and `detail` says why; the server SHOULD retry, and MUST + NOT silently give up without leaving this state visible. + enum: + - pending + - published + - failed + lastAttemptAt: + $ref: "#/components/schemas/date-time" + detail: + type: string + description: Why the last attempt failed, when it did. + required: + - target + - state + + artifact-signature: + type: object + description: | + A detached signature over an artifact format's bytes. + + signatures/signature.md calls for an indication of the hash algorithm, + an indicator of the certificate used, and the intermediate and signing + certificates. This carries them, plus the transparency-log entry where + the scheme has one. A signature that is itself publicly logged is far + harder to backdate. + additionalProperties: false + properties: + signatureType: + type: string + description: The scheme, so a consumer knows how to verify rather than having to guess. + enum: + - jws + - jsf + - cose + - pgp + - x509-cms + - sigstore-bundle + - ssh + url: + type: string + format: url + description: Direct download URL for the detached signature. + algorithm: + type: string + description: Hash algorithm the signature was computed over, e.g. SHA-256. + keyId: + type: string + description: Key identifier the signature was produced with, where the scheme has one. + certificateUrl: + type: string + format: url + description: Signing certificate, where verification needs one. + certificateChainUrl: + type: string + format: url + description: Intermediate certificates between the signing certificate and a trusted root. + transparencyLogUrl: + type: string + format: url + description: Entry in a signature transparency log, such as Rekor. + signedAt: + $ref: "#/components/schemas/date-time" + required: + - signatureType + - url + + access-policy-status: + type: object + description: An object's declared access policy alongside the one actually enforced. + additionalProperties: false + properties: + uuid: + description: The object the policy applies to. + $ref: "#/components/schemas/uuid" + declared: + description: | + What this object sets for itself. Absent when it declares nothing + and relies entirely on inheritance. + $ref: "#/components/schemas/access-policy" + effective: + description: | + What is enforced: the narrowest policy declared between this object + and the root, with `shared` entitlements intersected. + $ref: "#/components/schemas/access-policy" + inheritedFrom: + description: | + The ancestor that constrained the answer, so a publisher can fix the + cause rather than the symptom. + + Present whenever an ancestor is what makes the effective policy + narrower than this object's own declaration, which includes the case + where the object declares something of its own and is overruled. An + ancestor that merely agrees is not the cause and is not reported. + $ref: "#/components/schemas/uuid" + mirrors: + type: array + description: | + How far mirroring has got, per target. Absent where the object is + mirrored nowhere, or where the server does not mirror at all. + items: + $ref: "#/components/schemas/mirror-status" + required: + - uuid + - effective + + publication: + type: object + description: | + One product this organisation has published, as the consumption API + serves it, alongside the access policy in force for it. + + The product is carried whole rather than flattened so that a publisher + can compare it byte for byte against what `GET /product/{uuid}` + returns; a summary in a different shape would have to be trusted rather + than checked. + additionalProperties: false + properties: + product: + $ref: "#/components/schemas/product" + accessPolicy: + description: Declared and effective policy, so the gap between them is visible here too. + $ref: "#/components/schemas/access-policy-status" + releaseCount: + type: integer + minimum: 0 + description: How many releases exist beneath this product. + required: + - product + - accessPolicy + + published-release: + type: object + description: One release this organisation has published, with what a consumer would find in it. + additionalProperties: false + properties: + release: + $ref: "#/components/schemas/productRelease" + accessPolicy: + $ref: "#/components/schemas/access-policy-status" + collectionVersion: + type: integer + minimum: 0 + description: | + Version of this release's current collection, or 0 where no + collection has been published yet, a release a consumer can + resolve and find nothing in. + artifactCount: + type: integer + minimum: 0 + description: How many artifacts the current collection holds. + required: + - release + - accessPolicy + + paginated-publication-target-response: + description: A paginated response containing registered publication targets + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/publication-target" + required: + - results + + paginated-publication-response: + description: A paginated response containing this organisation's published products + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/publication" + required: + - results + + paginated-published-release-response: + description: A paginated response containing this organisation's published releases + allOf: + - $ref: "#/components/schemas/pagination-details" + - type: object + properties: + results: + type: array + items: + $ref: "#/components/schemas/published-release" + required: + - results + + parameters: + object-uuid: + name: uuid + in: path + required: true + description: UUID of the object. + schema: + $ref: "#/components/schemas/uuid" + artifact-uuid: + name: uuid + in: path + required: true + description: UUID of the TEA Artifact. + schema: + $ref: "#/components/schemas/uuid" + format-index: + name: formatIndex + in: path + required: true + description: | + Zero-based index of the format within the artifact's `formats` array. + Formats are addressed positionally because a media type is not unique + within an artifact: the same document is often published both + compressed and not. + schema: + type: integer + minimum: 0 + confirm-public: + name: confirm + in: query + required: false + description: | + Acknowledges an irreversible change. Required, with the value `public`, + on a request that sets `visibility` to `public`; ignored otherwise. + + A server MUST reject such a request without it, so that publishing to + the open web is something a caller states outright rather than + something a mistyped field does on its behalf. + schema: + type: string + enum: + - public + idempotency-key: + name: Idempotency-Key + in: header + required: false + description: | + A client-chosen key that makes a create safe to retry. + + Publication runs in release pipelines, and pipelines retry. Without + this, a timeout that actually succeeded produces a second object on the + next attempt, a duplicate discovered by a consumer rather than by the + publisher. A server supporting the key MUST return the original result + for a repeat of the same key rather than creating again. + schema: + type: string + maxLength: 255 + content-digest: + name: Content-Digest + in: header + required: false + description: | + Digest of the request body per RFC 9530, e.g. `sha-256=::`. + Where supplied, the server MUST verify it against the bytes received + and reject a mismatch rather than storing content that does not match + the checksum it will be published under. + schema: + type: string + + responses: + object-deleted: + description: | + The object was deleted and is no longer resolvable through the + consumption API. + publisher-bad-request: + description: The request body is invalid. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-unauthorized: + description: Authentication is required, or the credential was rejected. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-forbidden: + description: | + Authenticated, but not entitled to perform this operation on this + object. Distinct from 401 on purpose: a publisher debugging a pipeline + needs to know whether the credential was rejected or the permission + was. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-not-found: + description: No such object, or the caller may not see it. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-conflict: + description: | + The request conflicts with the object's current state: a create that + would duplicate an existing natural key, an update against a version + since superseded, or an access policy wider than the object's parent. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-mirroring-unsupported: + description: | + This server does not mirror to other TEA servers. Answered rather than + quietly ignoring the request, so a publisher is never left believing a + copy exists somewhere it does not. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-payload-too-large: + description: The uploaded content exceeds the size this server accepts. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + publisher-unsupported-media-type: + description: The supplied media type is not one this server accepts for the object. + content: + application/json: + schema: + $ref: "#/components/schemas/publisher-error-response" + product-written: + description: The product as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/product" + component-written: + description: The component as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/component" + product-release-written: + description: The product release as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/productRelease" + component-release-written: + description: The component release as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/release" + collection-written: + description: The newly published collection version. + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + artifact-written: + description: The artifact as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/artifact" + distribution-written: + description: The distribution as the consumption API will serve it. + content: + application/json: + schema: + $ref: "#/components/schemas/release-distribution" + access-policy-read: + description: The access policy in force for the object. + content: + application/json: + schema: + $ref: "#/components/schemas/access-policy-status" + publication-target-written: + description: The publication target as registered, without its credential. + content: + application/json: + schema: + $ref: "#/components/schemas/publication-target" + paginated-publication-target: + description: A paginated response containing registered publication targets. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-publication-target-response" + paginated-publication: + description: A paginated response containing this organisation's published products. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-publication-response" + paginated-published-release: + description: A paginated response containing this organisation's published releases. + content: + application/json: + schema: + $ref: "#/components/schemas/paginated-published-release-response" + + requestBodies: + write-product: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + name: + type: string + description: Product name. + identifiers: + type: array + description: | + Identifiers for the product. A server assigns the TEI itself + because it names the server's own authority over the object, + so a + publisher supplying one would be asserting something only the + server can know. + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-component: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + name: + type: string + description: Component name. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-product-release: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + product: + description: UUID of the product this release belongs to. + $ref: "#/components/schemas/uuid" + version: + type: string + description: Version of the release. + releaseDate: + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: Whether this release is a pre-release. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + components: + type: array + description: | + The components this release is composed of, optionally + pinning a specific component release. + + Present because the consumption specification lists + `components` among `productRelease`'s required members: a + publisher with no way to state it can only ever produce + releases a server has to serve as an empty list, which is a + claim about the product rather than a gap in the record. + + Omitted means unchanged on update, and empty on create. + items: + $ref: "#/components/schemas/component-ref" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-component-release: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + component: + description: UUID of the component this release belongs to. + $ref: "#/components/schemas/uuid" + version: + type: string + description: Version of the release. + releaseDate: + $ref: "#/components/schemas/date-time" + preRelease: + type: boolean + description: Whether this release is a pre-release. + identifiers: + type: array + items: + $ref: "#/components/schemas/identifier" + accessPolicy: + $ref: "#/components/schemas/access-policy" + write-publication-target: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + `uuid` and `domain` are absent by design: the server assigns the + first and derives the second from `rootUrl`, so the two cannot + disagree about which server a target actually is. + properties: + rootUrl: + type: string + format: uri + description: | + The remote server's TEA root, without a trailing slash. Must + be an absolute https URL, because a mirror carries a credential and + sending one over http would publish it to the network as well + as to the target. + description: + type: string + description: What this target is, for whoever reviews the list later. + credential: + type: string + writeOnly: true + description: | + Bearer credential to present when publishing to the target. + Never returned by any operation. + required: + - rootUrl + write-collection: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + updateReason: + description: Why this version was published. + $ref: "#/components/schemas/collection-update-reason" + accessPolicy: + $ref: "#/components/schemas/access-policy" + required: + - updateReason + write-distribution: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + `distributionId` is absent by design: the server assigns it, and + a publisher-supplied identifier would let one tenant claim + another's. It is derived from the release and the natural key + below, so re-publishing the same download is an update. + properties: + description: + type: string + description: | + What this channel or format is, in terms a human choosing how + to install would recognise. Required when there is no `url`, + and used as the natural key in that case. + url: + type: string + format: url + description: | + Direct download URL. Must be absolute and http(s): a relative + path would resolve against the consumer's own origin, and + other schemes ask a consumer to do something it did not + request. + signatureUrl: + type: string + format: url + description: Direct download URL for the detached signature. + identifiers: + type: array + description: | + Identifiers for this distribution specifically. Optional + because several real channels have no accepted purl type, + Homebrew and Scoop among them, and an identifier that names + a coordinate which does not resolve is worse than none, since + a consumer will follow it. + items: + $ref: "#/components/schemas/identifier" + checksums: + type: array + description: | + Recorded verbatim. This server does not hold the bytes and + cannot verify them, so these are the publisher's assertion, + not ours. + items: + $ref: "#/components/schemas/checksum" + anyOf: + - required: [url] + - required: [description] + write-artifact: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + collection: + description: | + UUID of the collection this artifact belongs to, which is the + UUID of its release. + $ref: "#/components/schemas/uuid" + name: + type: string + description: Human-readable name of the artifact. + type: + $ref: "#/components/schemas/artifact-type" + formats: + type: array + description: | + The representations this artifact is published in. A format + may carry a `url` when the publisher hosts the bytes itself; + otherwise they are uploaded to this server afterwards. + items: + $ref: "#/components/schemas/artifact-format" + distributionIds: + type: array + description: | + The distributions this artifact describes. Absent or empty + means it applies to all of them, which is what the + consumption specification says of the same field. + + It matters for exactly the case where an SBOM is not one + document: a Windows installer and a source tarball of the + same release have different contents, and an artifact that + cannot say which one it describes is attached to both + incorrectly. + items: + $ref: "#/components/schemas/uuid" + accessPolicy: + $ref: "#/components/schemas/access-policy" + required: + - collection + - name + - formats + update-artifact: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + description: | + Metadata only. Stored bytes are immutable: replacing content + means a new format or a new artifact, not an overwrite. + properties: + name: + type: string + type: + $ref: "#/components/schemas/artifact-type" + distributionIds: + type: array + description: | + Replaces the set of distributions this artifact describes. + An empty array means all of them. + items: + $ref: "#/components/schemas/uuid" + accessPolicy: + $ref: "#/components/schemas/access-policy" + +tags: + - name: TEA Publication + description: | + Operations that create, update and delete the objects the consumption API + serves. + - name: TEA Access Policy + description: | + Operations controlling who may read an object through the consumption + API: the publishing organisation alone, named counterparties, or anyone. + - name: TEA Publication Target + description: | + Registration of the remote TEA servers a publisher mirrors objects to. + Mirroring is a copy the receiving server then governs, so the set of + targets is configured deliberately rather than named in passing. diff --git a/spec/publisher/package-lock.json b/spec/publisher/package-lock.json new file mode 100644 index 0000000..f93e822 --- /dev/null +++ b/spec/publisher/package-lock.json @@ -0,0 +1,3225 @@ +{ + "name": "tea-publisher-spec", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tea-publisher-spec", + "devDependencies": { + "@redocly/cli": "^1.34.5", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@faker-js/faker": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", + "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", + "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz", + "integrity": "sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.26.0.tgz", + "integrity": "sha512-HedpXXYzzbaoutw6DFLWLDket2FwLkLpil4hGCZ1xYEIMTcivdfwEOISgdbLEWyG3HW52gTq2V9mOVJrONgiwg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.26.0.tgz", + "integrity": "sha512-1iKxXXE8415Cdv0yjG3G6hQnB5eVEsJce3QaawX8SjDn0mAS0ZM8fAbZZJD4ajvhC15cePvosSCut404KrIIvQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.53.0.tgz", + "integrity": "sha512-m7F5ZTq+V9mKGWYpX8EnZ7NjoqAU7VemQ1E2HAG+W/u0wpY1x0OmbxAXfGKFHCspdJk8UKlwPGrpcB8nay3P8A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0", + "@opentelemetry/otlp-exporter-base": "0.53.0", + "@opentelemetry/otlp-transformer": "0.53.0", + "@opentelemetry/resources": "1.26.0", + "@opentelemetry/sdk-trace-base": "1.26.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.53.0.tgz", + "integrity": "sha512-UCWPreGQEhD6FjBaeDuXhiMf6kkBODF0ZQzrk/tuQcaVDJ+dDQ/xhJp192H9yWnKxVpEjFrSSLnpqmX4VwX+eA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0", + "@opentelemetry/otlp-transformer": "0.53.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.53.0.tgz", + "integrity": "sha512-rM0sDA9HD8dluwuBxLetUmoqGJKSAbWenwD65KY9iZhUxdBHRLrIdrABfNDP7aiTjcgK8XFyTn5fhDz7N+W6DA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.53.0", + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0", + "@opentelemetry/sdk-logs": "0.53.0", + "@opentelemetry/sdk-metrics": "1.26.0", + "@opentelemetry/sdk-trace-base": "1.26.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.26.0.tgz", + "integrity": "sha512-vvVkQLQ/lGGyEy9GT8uFnI047pajSOVnZI2poJqVGD3nJ+B9sFGdlHNnQKophE3lHfnIH0pw2ubrCTjZCgIj+Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.26.0.tgz", + "integrity": "sha512-DelFGkCdaxA1C/QA0Xilszfr0t4YbGd3DjxiCDPh34lfnFr+VkkrjV9S8ZTJvAzfdKERXhfOxIKBoGPJwoSz7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.26.0.tgz", + "integrity": "sha512-CPNYchBE7MBecCSVy0HKpUISEeJOniWqcHaAHpmasZ3j9o6V3AyBzhRc90jdmemq0HOxDr6ylhUbDhBqqPpeNw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.53.0.tgz", + "integrity": "sha512-dhSisnEgIj/vJZXZV6f6KcTnyLDx/VuQ6l3ejuZpMpPlh9S1qMHiZU9NMmOkVkwwHkMy3G6mEBwdP23vUZVr4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.53.0", + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.26.0.tgz", + "integrity": "sha512-0SvDXmou/JjzSDOjUmetAAvcKQW6ZrvosU0rkbDGpXvvZN+pQF6JbK/Kd4hNdK4q/22yeruqvukXEJyySTzyTQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.26.0.tgz", + "integrity": "sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0", + "@opentelemetry/semantic-conventions": "1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.26.0.tgz", + "integrity": "sha512-Fj5IVKrj0yeUwlewCRwzOVcr5avTuNnMHWf7GPc1t6WaT78J6CJyF3saZ/0RkZfdeNO8IcBl/bNcWMVZBMRW8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.26.0", + "@opentelemetry/core": "1.26.0", + "@opentelemetry/propagator-b3": "1.26.0", + "@opentelemetry/propagator-jaeger": "1.26.0", + "@opentelemetry/sdk-trace-base": "1.26.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/cli": { + "version": "1.34.18", + "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.34.18.tgz", + "integrity": "sha512-xYt83IDBsQiw+eK0tSYMSjEsOdKpfP4jX1evma6nlsZdW+pYX0VUZDI1GdxngDDAH1gkpruJXSsPdUnIghtV9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "1.9.0", + "@opentelemetry/exporter-trace-otlp-http": "0.53.0", + "@opentelemetry/resources": "1.26.0", + "@opentelemetry/sdk-trace-node": "1.26.0", + "@opentelemetry/semantic-conventions": "1.27.0", + "@redocly/config": "0.22.0", + "@redocly/openapi-core": "1.34.18", + "@redocly/respect-core": "1.34.18", + "abort-controller": "3.0.0", + "chokidar": "3.5.3", + "colorette": "1.4.0", + "core-js": "3.32.1", + "dotenv": "16.4.7", + "form-data": "4.0.6", + "get-port-please": "3.0.1", + "glob": "7.2.3", + "handlebars": "4.7.9", + "js-yaml": "4.3.0", + "mobx": "6.12.3", + "pluralize": "8.0.0", + "react": "^17.0.0 || ^18.2.0 || ^19.2.1", + "react-dom": "^17.0.0 || ^18.2.0 || ^19.2.1", + "redoc": "2.5.0", + "semver": "7.7.4", + "simple-websocket": "9.1.0", + "styled-components": "6.4.1", + "yargs": "17.0.1" + }, + "bin": { + "openapi": "bin/cli.js", + "redocly": "bin/cli.js" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@redocly/cli/node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@redocly/config": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", + "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.34.18", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.18.tgz", + "integrity": "sha512-UyKIm0wTPw5BcY7Z2PkbK1Ma260um96LSBWXHrdSMe+ZV0EPMyDfAcUcjjm3qEiGST9OK/1TriekdPCZkn4Q3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "8.11.2", + "@redocly/config": "0.22.0", + "colorette": "1.4.0", + "https-proxy-agent": "7.0.6", + "js-levenshtein": "1.1.6", + "js-yaml": "4.3.0", + "minimatch": "5.1.9", + "pluralize": "8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@redocly/respect-core": { + "version": "1.34.18", + "resolved": "https://registry.npmjs.org/@redocly/respect-core/-/respect-core-1.34.18.tgz", + "integrity": "sha512-gMF4o3oscRFUcHtPTT3YP52sSMDyFYiMexOV/tZGvoJSZlh7h1G6SBveDpfHCYBk9iaUdhCEFWve3YHJk3LlRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@faker-js/faker": "7.6.0", + "@redocly/ajv": "8.11.2", + "@redocly/openapi-core": "1.34.18", + "better-ajv-errors": "1.2.0", + "colorette": "2.0.20", + "concat-stream": "2.0.0", + "cookie": "0.7.2", + "dotenv": "16.4.7", + "form-data": "4.0.6", + "jest-diff": "29.7.0", + "jest-matcher-utils": "29.7.0", + "js-yaml": "4.3.0", + "json-pointer": "0.6.2", + "jsonpath-plus": "10.3.0", + "open": "10.1.0", + "openapi-sampler": "1.7.0", + "outdent": "0.8.0", + "set-cookie-parser": "2.7.1", + "undici": "6.27.0" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@redocly/respect-core/node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/respect-core/node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", + "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/better-ajv-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz", + "integrity": "sha512-UW+IsFycygIo7bclP9h5ugkNH8EjCSgqyFB/yQ4Hqqa1OEYDtb0uFIkYE0b6+CjkgJYVM5UKI/pJPxjYe9EZlA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "@humanwhocodes/momoa": "^2.0.2", + "chalk": "^4.1.2", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0 < 4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "peerDependencies": { + "ajv": "4.11.8 - 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js": { + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.1.tgz", + "integrity": "sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decko": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz", + "integrity": "sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==", + "dev": true + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dompurify": { + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", + "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port-please": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.0.1.tgz", + "integrity": "sha512-R5pcVO8Z1+pVDu8Ml3xaJCEkBiiy1VQN9za0YqH8GIi1nIqD4IzQhzY6dDzMRtdS1lyiGlucRzm8IN8wtLIXng==", + "dev": true, + "license": "MIT" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "foreach": "^2.0.4" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpath-plus": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", + "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mobx": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.12.3.tgz", + "integrity": "sha512-c8NKkO4R2lShkSXZ2Ongj1ycjugjzFFo/UswHBnS62y07DMcTc9Rvo03/3nRyszIvwPNljlkd4S828zIBv/piw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-9.2.2.tgz", + "integrity": "sha512-ShszmQzR/VrhU3M0cQ7DA/s8qNcLcF2emSuudJ/TnDILS3C1Im48mdaG6CpyjZHy8+WqgXUCC9mPqSRIwPPMuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mobx-react-lite": "^4.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.1.1.tgz", + "integrity": "sha512-iUxiMpsvNraCKXU+yPotsOncNNmyeS2B5DKL+TL6Tar/xm+wwNJAubJmtRSeAoYawdZqwv8Z/+5nPRHeQxTiXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-sampler": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.7.0.tgz", + "integrity": "sha512-fWq32F5vqGpgRJYIarC/9Y1wC9tKnRDcCOjsDJ7MIcSv2HsE7kNifcXIZ8FVtNStBUWxYrEk/MKqVF0SwZ5gog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.7", + "fast-xml-parser": "^5.3.4", + "json-pointer": "0.6.2" + } + }, + "node_modules/outdent": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz", + "integrity": "sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz", + "integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/protobufjs": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-tabs": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.1.1.tgz", + "integrity": "sha512-CPiuKoMFf89B7QlbFfdBD9XmUWiE3qudQputMVZB8GQvPJZRX/gqjDaDWOPDwGinEfpJKEuBCkGt83Tt4efeyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redoc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.5.0.tgz", + "integrity": "sha512-NpYsOZ1PD9qFdjbLVBZJWptqE+4Y6TkUuvEOqPUmoH7AKOmPcE+hYjotLxQNTqVoWL4z0T2uxILmcc8JGDci+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.4.0", + "classnames": "^2.3.2", + "decko": "^1.2.0", + "dompurify": "^3.2.4", + "eventemitter3": "^5.0.1", + "json-pointer": "^0.6.2", + "lunr": "^2.3.9", + "mark.js": "^8.11.1", + "marked": "^4.3.0", + "mobx-react": "^9.1.1", + "openapi-sampler": "^1.5.0", + "path-browserify": "^1.0.1", + "perfect-scrollbar": "^1.5.5", + "polished": "^4.2.2", + "prismjs": "^1.29.0", + "prop-types": "^15.8.1", + "react-tabs": "^6.0.2", + "slugify": "~1.4.7", + "stickyfill": "^1.1.1", + "swagger2openapi": "^7.0.8", + "url-template": "^2.0.8" + }, + "engines": { + "node": ">=6.9", + "npm": ">=3.0.0" + }, + "peerDependencies": { + "core-js": "^3.1.4", + "mobx": "^6.0.4", + "react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5" + } + }, + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/simple-websocket": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/simple-websocket/-/simple-websocket-9.1.0.tgz", + "integrity": "sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "debug": "^4.3.1", + "queue-microtask": "^1.2.2", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0", + "ws": "^7.4.2" + } + }, + "node_modules/slugify": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz", + "integrity": "sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stickyfill": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stickyfill/-/stickyfill-1.1.1.tgz", + "integrity": "sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strnum": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/styled-components": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.4.1.tgz", + "integrity": "sha512-ADu2dF53esUzzM4I0ewxhxFtsDd6v4V6dNkg3vG0iFKhnt06sJneTZnRvujAosZwW0XD58IKgGMQoqri4wHRqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "stylis": "4.3.6" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "css-to-react-native": ">= 3.2.0", + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-native": ">= 0.68.0" + }, + "peerDependenciesMeta": { + "css-to-react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", + "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js-replace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", + "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", + "dev": true, + "license": "BSD" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", + "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + } + } +} diff --git a/spec/publisher/package.json b/spec/publisher/package.json new file mode 100644 index 0000000..b2fe786 --- /dev/null +++ b/spec/publisher/package.json @@ -0,0 +1,15 @@ +{ + "name": "tea-publisher-spec", + "private": true, + "type": "module", + "description": "Builds spec/publisher/openapi.yaml from the consumption specification plus a publication overlay.", + "scripts": { + "build": "node build.mjs", + "check": "node build.mjs --check", + "lint": "redocly lint openapi.yaml" + }, + "devDependencies": { + "@redocly/cli": "^1.34.5", + "js-yaml": "^4.1.0" + } +}