Try   HackMD

Warg Record Publish API

Create Record (content already uploaded)

POST /package/<package-id>

{
    "record": "<base64(Envelope)>",
    "content_sources": [
        {
            "content_digest": "<content-digest>"
            "type": "http-anonymous",
            "url": "https://github.com/bytecodealliance/dog-facts/releases/download/v0.1.0/dog-facts-v0.1.0.wasm",
        },
    ]
}

Success

{
    "state": "published",
    "record_url": "/package/<package-id>/<record-id>",
}

Failure

{
    "state": "rejected",
    "reason": "content validation failed",
}

Below is future-looking design and can be implemented as needed.

Create Record (async / multi-step)

POST /package/<package-id>

{
    "record": "<base64(Envelope)>"
}
# 202 Accepted
{
    "url": "/package/<package-id>/<record-id>",
    "state": "pending",
    "content_needed": ["<content-digest>"],
    # optional; see below
    "content_endpoints": [
        # BYO storage
        {
            "type": "anonymous-http",        
        },
        # OR upload to registry-hosted storage
        {
            # If not specified, this endpoint will accept
            # any/all content from `content_needed`
            "content_digests": ["<content-digest>"],
            "type": "anonymous-http",
            "upload_url": "https://registry.bytecodealliance.org/content/<content-digest>",
        }
    ],
}

What if there are multiple pieces of content (multiple releases) or multiple available upload locations for content? Kyle

{
    "url": "/package/<package-id>/<record-id>",
    "state": "pending",
    # Content needed list can have multiple elements
    # indicating e.g. multiple releases were provided
    "content_needed": [
        {
            "content_digest": "<content-digest>",
            # Content_endpoints may have multiple elements
            # if there are multiple places content can be uploaded
            "content_endpoints": [
                {
                    "type": "anonymous-http",
                    "post_url": "https://registry.bytecodealliance.org/content/<content-digest>",
                }
            ]
        }
    ],
}

Content Update

POST /package/<package-id>/<record-id>

{
    "content_sources": [
        {
            "type": "http-anonymous",
            "url": "https://registry.bytecodealliance.org/content/<content-digest>",
        },
    ]
}
{
    "url": "/package/<package-id>/<record-id>",
    "state": "processing",
}

Record Status

GET /package/<package-id>/<record-id>

{
    "url": "/package/<package-id>/<record-id>",
    "state": "published",
}

Content Endpoint Examples

Content endpoints specify acceptable content sources and may specify how to upload to a source. The type field determines how the rest of the endpoint data is interpreted.

# BYO storage
{
    "type": "anonymous-http"
}
# Restricted BYO storage
{
    "type": "anonymous-http",
    "allowed_urls": [
        "https://registry.bytecodealliance.org/content/*",
    ]
}
# Registry-provided storage
{
    "type": "anonymous-http",
    "upload_url": "https://registry.bytecodealliance.org/content/<content-digest>",
}
# OCI
{
    "type": "oci-artifact",
}
# IPFS
{
    "type": "ipfs"
}

upload to content endpoint; POST to URL with content_sources

Protobuf sketch

message Record {
    // From `package.proto`
    warg.package.Envelope record = 1;
    repeated ContentStore content_sources = 2;
}

message ContentSource {
    // May be omitted from `supported_content_sources` if
    // supported for all content.
    string content_digest = 1;
    // e.g. `http-anonymous`
    string type = 2;
    // Schema depends on `type` and whether it appears in
    // `content_sources` or `supported_content_sources`
    google.protobuf.Struct params = 3;
}

message RecordStatus {
    RecordState state = 1;
    // Present when returned by "create record" if non-terminal state
    string status_url = 2;
    // Required for status "rejected"
    string reason = 3;
    
    // Pending
    repeated string content_needed = 4;
    repeated ContentSource supported_content_sources = 5;
    
    // Published
    string record_url = 6;
}

enum RecordState {
    RECORD_STATE_UNSPECIFIED = 0;
    RECORD_STATE_PENDING = 1;
    RECORD_STATE_PROCESSING = 2;
    RECORD_STATE_PUBLISHED = 3;
    RECORD_STATE_REJECTED = 4;
}

JSONPB

# Record
{
    "record": {
        "contents": "<base64(contents)>",
        "key_id": "...",
        "signature": "...",
    },
    "content_sources": [
        {
            "content_digest": "<content-digest>",
            "type": "http-anonymous",
            "params": {
                "url": "..."
            }
        }
    ]
}

# RecordStatus
{
    "state": "RECORD_STATE_PENDING",
    "status_url": "...",
    "content_needed": ["<content-digest>"],
    "supported_content_sources": [
        {
            "type": "http-anonymous"
        }
    ]
}