# at.happyproto.registry.putProject

> Published by [happyproto.at](https://lexicon.garden/identity/did:plc:mo7vq4jbioxwafy5zkcc3eux)

✓ This is the authoritative definition for this NSID.

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:mo7vq4jbioxwafy5zkcc3eux/at.happyproto.registry.putProject)
- [Documentation](https://lexicon.garden/lexicon/did:plc:mo7vq4jbioxwafy5zkcc3eux/at.happyproto.registry.putProject/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:mo7vq4jbioxwafy5zkcc3eux/at.happyproto.registry.putProject/examples)

## Definitions

### `at.happyproto.registry.putProject`

**Type**: `procedure`

Create or update a plugin project in the caller's repo. The first call writes the site.standard.publication, the at.happyproto.registry.project and the software.release.project, in that order, so each is indexed after what it depends on. Later calls update the publication and the at.happyproto.registry.project only; the project record itself is never changed.

#### Input

**Encoding**: `application/json`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | `string` | Yes | The project's name, which is the record key of its software.release.project: 1 to 64 lowercase letters, digits and interior hyphens. |
| `project` | `ref` → `#project` | Yes |  |
| `publication` | `ref` → `#publication` | Yes |  |
| `swapCid` | `string` (cid) | No | Update only if the caller's at.happyproto.registry.project record still has this CID, so a concurrent update is not silently overwritten. |
| `validateOnly` | `boolean` | No | Check the input against every rule the registry applies, and write nothing. Works without authentication, but only a signed-in call is also checked against the caller's existing records. |

#### Output

**Encoding**: `application/json`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `created` | `boolean` | No | True when this call created the project. Absent when validateOnly was set. |
| `project` | `ref` → `at.happyproto.registry.defs#ref` | No | The software.release.project. Absent when validateOnly was set. |
| `publication` | `ref` → `at.happyproto.registry.defs#ref` | No | The site.standard.publication. Absent when validateOnly was set. |
| `sidecar` | `ref` → `at.happyproto.registry.defs#ref` | No | The at.happyproto.registry.project. Absent when validateOnly was set. |
| `valid` | `boolean` | Yes | Always true; invalid input is an error, not a result. |

#### Errors

- **AuthRequired**: The caller's identity could not be determined, so there is no repo to write to.
- **NotConfigured**: The registry has no identity configured. An operator problem, not a caller's.
- **InvalidRecord**: The input breaks a rule the registry applies, so it would refuse the records. The message names the field.
- **Upstream**: A record could not be written to the caller's repo. Records written before the failure stay, and the same call can be made again.
- **InvalidSwap**: The caller's at.happyproto.registry.project record no longer has the CID given in swapCid.

### `at.happyproto.registry.putProject#project`

**Type**: `object`

What the registry writes to the project's at.happyproto.registry.project.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `authors` | `array` | Yes |  |
| `keywords` | `array` | No |  |
| `pluginType` | `string` | Yes |  |
| `security` | `array` | Yes |  |

### `at.happyproto.registry.putProject#publication`

**Type**: `object`

What the registry writes to the project's site.standard.publication.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `description` | `string` | No |  |
| `icon` | `blob` | No | A blob already uploaded to the caller's repo: a PNG, JPEG, WebP, GIF or AVIF image, the raster types the registry copies and serves. SVG is refused, since it can carry script. |
| `name` | `string` | Yes | The plugin's display name. |

## Raw Schema

```json
{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "main": {
      "description": "Create or update a plugin project in the caller's repo. The first call writes the site.standard.publication, the at.happyproto.registry.project and the software.release.project, in that order, so each is indexed after what it depends on. Later calls update the publication and the at.happyproto.registry.project only; the project record itself is never changed.",
      "errors": [
        {
          "description": "The caller's identity could not be determined, so there is no repo to write to.",
          "name": "AuthRequired"
        },
        {
          "description": "The registry has no identity configured. An operator problem, not a caller's.",
          "name": "NotConfigured"
        },
        {
          "description": "The input breaks a rule the registry applies, so it would refuse the records. The message names the field.",
          "name": "InvalidRecord"
        },
        {
          "description": "A record could not be written to the caller's repo. Records written before the failure stay, and the same call can be made again.",
          "name": "Upstream"
        },
        {
          "description": "The caller's at.happyproto.registry.project record no longer has the CID given in swapCid.",
          "name": "InvalidSwap"
        }
      ],
      "input": {
        "encoding": "application/json",
        "schema": {
          "properties": {
            "name": {
              "description": "The project's name, which is the record key of its software.release.project: 1 to 64 lowercase letters, digits and interior hyphens.",
              "maxLength": 64,
              "minLength": 1,
              "type": "string"
            },
            "project": {
              "ref": "#project",
              "type": "ref"
            },
            "publication": {
              "ref": "#publication",
              "type": "ref"
            },
            "swapCid": {
              "description": "Update only if the caller's at.happyproto.registry.project record still has this CID, so a concurrent update is not silently overwritten.",
              "format": "cid",
              "type": "string"
            },
            "validateOnly": {
              "default": false,
              "description": "Check the input against every rule the registry applies, and write nothing. Works without authentication, but only a signed-in call is also checked against the caller's existing records.",
              "type": "boolean"
            }
          },
          "required": [
            "name",
            "publication",
            "project"
          ],
          "type": "object"
        }
      },
      "output": {
        "encoding": "application/json",
        "schema": {
          "properties": {
            "created": {
              "description": "True when this call created the project. Absent when validateOnly was set.",
              "type": "boolean"
            },
            "project": {
              "description": "The software.release.project. Absent when validateOnly was set.",
              "ref": "at.happyproto.registry.defs#ref",
              "type": "ref"
            },
            "publication": {
              "description": "The site.standard.publication. Absent when validateOnly was set.",
              "ref": "at.happyproto.registry.defs#ref",
              "type": "ref"
            },
            "sidecar": {
              "description": "The at.happyproto.registry.project. Absent when validateOnly was set.",
              "ref": "at.happyproto.registry.defs#ref",
              "type": "ref"
            },
            "valid": {
              "description": "Always true; invalid input is an error, not a result.",
              "type": "boolean"
            }
          },
          "required": [
            "valid"
          ],
          "type": "object"
        }
      },
      "type": "procedure"
    },
    "project": {
      "description": "What the registry writes to the project's at.happyproto.registry.project.",
      "properties": {
        "authors": {
          "items": {
            "ref": "at.happyproto.registry.project#author",
            "type": "ref"
          },
          "minLength": 1,
          "type": "array"
        },
        "keywords": {
          "items": {
            "maxGraphemes": 32,
            "maxLength": 320,
            "type": "string"
          },
          "maxLength": 20,
          "type": "array"
        },
        "pluginType": {
          "knownValues": [
            "auth",
            "library",
            "interpreter"
          ],
          "type": "string"
        },
        "security": {
          "items": {
            "ref": "at.happyproto.registry.project#contact",
            "type": "ref"
          },
          "minLength": 1,
          "type": "array"
        }
      },
      "required": [
        "pluginType",
        "authors",
        "security"
      ],
      "type": "object"
    },
    "publication": {
      "description": "What the registry writes to the project's site.standard.publication.",
      "properties": {
        "description": {
          "maxGraphemes": 300,
          "maxLength": 3000,
          "type": "string"
        },
        "icon": {
          "accept": [
            "image/png",
            "image/jpeg",
            "image/webp",
            "image/gif",
            "image/avif"
          ],
          "description": "A blob already uploaded to the caller's repo: a PNG, JPEG, WebP, GIF or AVIF image, the raster types the registry copies and serves. SVG is refused, since it can carry script.",
          "maxSize": 1000000,
          "type": "blob"
        },
        "name": {
          "description": "The plugin's display name.",
          "maxGraphemes": 64,
          "maxLength": 640,
          "minLength": 1,
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    }
  },
  "id": "at.happyproto.registry.putProject",
  "lexicon": 1
}
```
