{
  "service": "Nightcord Storage",
  "version": "2.0.0",
  "description": "Object storage proxy with SEKAI v2 resource facade. Legacy upload paths remain; new clients should prefer /v2/upload and typed resolve URLs.",
  "hosts": {
    "storage": "https://storage.nightcord.de5.net",
    "r2": "https://r2.nightcord.de5.net",
    "note": "Both hosts hit this Worker when bound. Prefer the media host for public SEKAI GETs; uploads may use either host."
  },
  "sekaiv2": {
    "upload": {
      "method": "PUT",
      "path": "/v2/upload",
      "headers": {
        "X-Filename": "percent-encoded original filename (required)",
        "Content-Type": "MIME type",
        "Content-Length": "bytes",
        "X-Sekai-Kind": "image | file | sticker (optional; inferred from MIME)",
        "X-Image-Width": "optional int",
        "X-Image-Height": "optional int"
      },
      "response": {
        "uuid": "resource id (use as SEKAI payload)",
        "key": "same as uuid",
        "type": "MIME",
        "size": "kilobytes (float)",
        "size_bytes": "bytes",
        "name": "original filename",
        "kind": "image | file | sticker",
        "url": "/images/{uuid} or /files/{uuid} or /stickers/{uuid}",
        "w": "optional",
        "h": "optional"
      },
      "example": "curl -X PUT https://r2.nightcord.de5.net/v2/upload -H \"X-Filename: photo.jpg\" -H \"Content-Type: image/jpeg\" --data-binary @photo.jpg"
    },
    "resolve": {
      "methods": [
        "GET",
        "HEAD"
      ],
      "paths": [
        "/images/{uuid}",
        "/files/{uuid}",
        "/stickers/{uuid}"
      ],
      "notes": [
        "UUID is a standard UUID v4 string.",
        "Objects are stored under AttachFiles/sekai/{uuid}{ext} on OSS.",
        "Public Cache-Control: immutable (long TTL) for successful GETs."
      ]
    },
    "meta": {
      "method": "GET",
      "path": "/v2/meta/{uuid}",
      "description": "JSON metadata written at upload time (best-effort)."
    },
    "message_payload": {
      "image": "<$SEKAI:Image:w=…;h=…;name=…:{uuid}>",
      "file": "<$SEKAI:Files:type=…;size=…;name=…:{uuid}>",
      "custom_stamp": "<$SEKAI:Stamp:custom=true:{uuid}>"
    }
  },
  "legacy": {
    "upload": {
      "method": "PUT",
      "path": "/",
      "headers": [
        "X-Filename",
        "Content-Type",
        "Content-Length"
      ],
      "optional": [
        "X-Safe-Path",
        "X-Chunk-Index / X-Chunk-Total / X-File-ID (chunked)"
      ],
      "response": {
        "key": "{uid}/{fileUuid}.ext",
        "url": "/{key}",
        "size": "bytes"
      }
    },
    "resolve": {
      "methods": [
        "GET",
        "HEAD",
        "DELETE"
      ],
      "path": "/{key}",
      "chunked": "/chunked/{inner}"
    }
  },
  "caching": {
    "eligible": "Public media (images/files/stickers, legacy keys). Exclude / and /v2/* from cache eligibility.",
    "see": "Cloudflare Cache Rules on storage.* and r2.*"
  },
  "links": {
    "self_html": "https://r2.nightcord.de5.net/",
    "self_json": "https://r2.nightcord.de5.net/?format=json",
    "self_markdown": "https://r2.nightcord.de5.net/?format=md",
    "sekaiv2_docs": "https://r2.nightcord.de5.net/v2",
    "accept_markdown": "Send Accept: text/markdown for this document as Markdown (agents)."
  }
}