<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.32 (Ruby 3.3.0) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

]>


<rfc ipr="trust200902" docName="draft-gondwana-jmap-blobext-03" category="std" consensus="true" submissionType="IETF" updates="8620, 9404" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="JMAP Blob Extended">JMAP Blob Extensions</title>

    <author initials="B." surname="Gondwana" fullname="Bron Gondwana">
      <organization>Fastmail</organization>
      <address>
        <email>brong@fastmailteam.com</email>
      </address>
    </author>

    <date year="2026" month="March" day="18"/>

    
    
    <keyword>Internet-Draft</keyword>

    <abstract>


<?line 30?>

<t>The JMAP base protocol (RFC8620) provides the ability to upload and download
arbitrary binary data.  This binary data is called a "blob", and can be used
in all other JMAP extensions.</t>

<t>The JMAP blob extension (RFC9404) added additional ways to create and access
blobs by making inline method calls within a standard JMAP request.</t>

<t>This extension adds more methods to work with blobs, including handling large
blobs by processing them in chunks (building on RFC9404's blob construction
support), and providing server-side blob conversion operations: image format
conversion, archive creation and extraction (zip, tar, cpio), compression
and decompression, and delta/patch operations.</t>



    </abstract>



  </front>

  <middle>


<?line 45?>

<section anchor="introduction"><name>Introduction</name>

<t>The JMAP Blob extension (<xref target="JMAP-BLOB"/> — JMAP Blob Management) offers additional
ways to create blobs, and query where they are used.</t>

<t>This extension builds on that work, offering ways to find more information about
the internal structure of the server's blob store in order to work efficiently
with it, and a new Blob/convert method for server-side blob transformations
including image format conversion, archive creation and extraction, compression
and decompression, and delta/patch operations.</t>

<section anchor="conventions-used-in-this-document"><name>Conventions Used in This Document</name>

<t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>

<?line -18?>

</section>
</section>
<section anchor="addition-to-the-capabilities-object"><name>Addition to the Capabilities Object</name>

<t>The capabilities object is returned as part of the JMAP Session
object; see <xref target="JMAP-CORE"/>, Section 2.</t>

<t>This document defines an additional capability URI.</t>

<section anchor="urnietfparamsjmapblobext"><name>urn:ietf:params:jmap:blobext</name>

<t>The capability <spanx style="verb">urn:ietf:params:jmap:blobext</spanx> being present in the
"accountCapabilities" property of an account represents support for
these extended properties on that account.  This capability depends
on <spanx style="verb">urn:ietf:params:jmap:blob</spanx> (<xref target="JMAP-BLOB"/>); both <bcp14>MUST</bcp14> be present
in the account's "accountCapabilities" and in the request's <spanx style="verb">using</spanx>
array.  If this capability is present in one or more
"accountCapabilities" properties then the server <bcp14>MUST</bcp14> also include
the key in the "capabilities" property.</t>

<t>The value of this property in the JMAP session "capabilities"
property <bcp14>MUST</bcp14> be an empty object.</t>

<t>The value of this property in an account's "accountCapabilities"
property is an object that <bcp14>MUST</bcp14> contain the following information
on server capabilities and permissions for that account:</t>

<t><list style="symbols">
  <t>resumableUploadUrl: "String|null"  <vspace blankLines='1'/>
If present, a <xref target="URI-TEMPLATE"/> which supports <xref target="HTTP-RESUMABLE-UPLOADS"/>.
  This <bcp14>MAY</bcp14> be the same as the uploadUrl, and has the same keys.</t>
  <t>chunkSize: "UnsignedInt|null"  <vspace blankLines='1'/>
A hint indicating the preferred chunk size in octets.  If a
  client uploads blobs with exactly this size except for the
  final chunk, and uses Blob/upload with DataSourceObjects
  referencing these chunks, the server can optimise storage of
  these chunks.  Servers <bcp14>MUST</bcp14> allow other sizes for the
  individual data blocks in Blob/upload though, and will then
  choose whether to store them as an array of blobs still, or
  to combine them.</t>
  <t>supportedImageTypes: "String[]"  <vspace blankLines='1'/>
The media types (<xref target="MEDIA-TYPES"/>) supported for ImageConvertRecipe.</t>
  <t>supportedArchiveTypes: "String[]"  <vspace blankLines='1'/>
The archive MIME types supported for ArchiveRecipe and UnArchiveRecipe.
  Defined values are "application/zip", "application/x-tar", and
  "application/x-cpio".</t>
  <t>supportedCompressionTypes: "String[]"  <vspace blankLines='1'/>
The compression MIME types supported for CompressRecipe and
  UnCompressRecipe.  Defined values are "application/gzip",
  "application/x-bzip2", "application/x-xz", and "application/zstd".</t>
  <t>supportedPatchTypes: "String[]"  <vspace blankLines='1'/>
The delta/patch media types supported for DeltaRecipe and
  PatchRecipe.  Defined values are "application/x-rdiff-delta",
  "application/x-bsdiff", and "text/x-diff" (unified diff).
  An empty array means no delta/patch operations are supported.</t>
  <t>maxConvertSize: "UnsignedInt|null"  <vspace blankLines='1'/>
If supplied, the maximum size in octets of any single input
  blob to a Blob/convert operation.  Requests referencing a blob
  larger than this value <bcp14>MUST</bcp14> be rejected with a "tooLarge"
  SetError.  If null, the server does not advertise a specific
  limit but <bcp14>MAY</bcp14> still reject blobs that are too large.</t>
  <t>maxArchiveEntries: "UnsignedInt|null"  <vspace blankLines='1'/>
If supplied, the maximum number of entries allowed in an
  ArchiveRecipe.  Requests exceeding this limit <bcp14>MUST</bcp14> be rejected
  with a "tooLarge" SetError.  If null, the server does not
  advertise a specific limit but <bcp14>MAY</bcp14> still reject requests with
  too many entries.</t>
  <t>maxImageDimension: "UnsignedInt|null"  <vspace blankLines='1'/>
If supplied, the maximum value accepted for <spanx style="verb">width</spanx> or <spanx style="verb">height</spanx>
  in an ImageConvertRecipe, in pixels.  Requests exceeding this
  limit <bcp14>MUST</bcp14> be rejected with a "tooLarge" SetError.  If null,
  the server does not advertise a specific limit but <bcp14>MAY</bcp14> still
  reject requests with dimensions that are too large.</t>
</list></t>

<section anchor="capability-example"><name>Capability Example</name>

<figure><sourcecode type="json"><![CDATA[
{
  "urn:ietf:params:jmap:blobext": {
    "resumableUploadUrl": null,
    "chunkSize": 5242880,
    "supportedImageTypes": [
      "image/png",
      "image/jpeg",
      "image/gif"
    ],
    "supportedArchiveTypes": [
      "application/zip",
      "application/x-tar"
    ],
    "supportedCompressionTypes": [
      "application/gzip",
      "application/x-bzip2",
      "application/zstd"
    ],
    "supportedPatchTypes": [
      "application/x-rdiff-delta",
      "text/x-diff"
    ],
    "maxConvertSize": 104857600,
    "maxArchiveEntries": 10000,
    "maxImageDimension": 8192
  }
}
]]></sourcecode></figure>

</section>
</section>
<section anchor="additions-to-blobget"><name>Additions to Blob/get</name>

<t>When this capability is present, Blob/get accepts an additional
request argument:</t>

<t><list style="symbols">
  <t>dataSourceProperties: "String[]" (default: ["blobId", "size"])
If supplied, only the properties listed in the array are returned
for each DataSourceObject in the <spanx style="verb">chunks</spanx> array.  If omitted, the
default of <spanx style="verb">["blobId", "size"]</spanx> is used.  Available properties
include <spanx style="verb">blobId</spanx>, <spanx style="verb">size</spanx>, <spanx style="verb">offset</spanx>, <spanx style="verb">length</spanx>, <spanx style="verb">position</spanx>, and
<spanx style="verb">digest:*</spanx> values (e.g. <spanx style="verb">digest:sha-256</spanx>).</t>
</list></t>

<t>Blob/get also returns an additional response property (returned by
default when this capability is included in <spanx style="verb">using</spanx>):</t>

<t><list style="symbols">
  <t>chunks: "DataSourceObject[]"  <vspace blankLines='1'/>
An array of one or more data source objects (as defined in <xref target="JMAP-BLOB"/>,
  Section 4.2).  The blob is reconstructed by concatenating the data
  from each data source object in the listed order.  While it is
  expected that each data source object will reference the entire
  underlying chunk blob, the server <bcp14>MAY</bcp14> return offset and length values
  that select only a portion of a chunk's blob.  The client <bcp14>MUST</bcp14> use
  the offset and length to determine which octets to read from each
  chunk.</t>
</list></t>

</section>
<section anchor="additions-to-datasourceobject"><name>Additions to DataSourceObject</name>

<t>When this capability is present, the DataSourceObject (as defined in
<xref target="JMAP-BLOB"/>, Section 4.2) is extended with the following additional
properties.  These apply both to the <spanx style="verb">chunks</spanx> returned by Blob/get
and to DataSourceObjects used in Blob/upload.  The <spanx style="verb">offset</spanx> and
<spanx style="verb">length</spanx> properties are already defined in <xref target="JMAP-BLOB"/>; they are
listed here to document their use in the <spanx style="verb">chunks</spanx> response context,
where they describe the range of each chunk's underlying data source
that contributes to the containing blob.</t>

<t><list style="symbols">
  <t>offset: "UnsignedInt|null"
The offset within the data source from which to start copying
octets (see <xref target="JMAP-BLOB"/>).  <bcp14>MUST</bcp14> fit within the data source
(i.e. offset <bcp14>MUST</bcp14> be less than or equal to the data source size).
If null, defaults to 0 (the start of the data source).</t>
  <t>length: "UnsignedInt|null"
The number of octets to copy from the data source (see
<xref target="JMAP-BLOB"/>).  <bcp14>MUST</bcp14> fit within the data source (i.e. offset +
length <bcp14>MUST</bcp14> be less than or equal to the data source size).  If
null, copy from <spanx style="verb">offset</spanx> to the end of the data source.</t>
  <t>size: "UnsignedInt|null"
The full size of the chunk's underlying data source in octets.</t>
  <t>position: "UnsignedInt|null"
The byte offset of the start of this chunk within the outer
(containing) blob.</t>
</list></t>

<t>If a <spanx style="verb">digest:*</spanx> property (e.g. <spanx style="verb">digest:sha</spanx>, <spanx style="verb">digest:sha-256</spanx>) is
included in <spanx style="verb">dataSourceProperties</spanx>, each DataSourceObject in the
<spanx style="verb">chunks</spanx> array will include the corresponding digest value computed
over the octets that this chunk contributes (i.e. after applying
<spanx style="verb">offset</spanx> and <spanx style="verb">length</spanx>).</t>

<t>When a server provides <spanx style="verb">size</spanx>, <spanx style="verb">position</spanx>, or <spanx style="verb">digest:*</spanx> values in
a Blob/get response, it <bcp14>MUST</bcp14> calculate them correctly.  When a
DataSourceObject containing <spanx style="verb">size</spanx>, <spanx style="verb">position</spanx>, or <spanx style="verb">digest:*</spanx> values
is used in Blob/upload, the server <bcp14>MUST</bcp14> reject the object if any
provided value does not match the actual data.</t>

</section>
<section anchor="additions-to-blobupload"><name>Additions to Blob/upload</name>

<t>When this capability is present, Blob/upload (<xref target="JMAP-BLOB"/>, Section 4)
gains the following additional request property:</t>

<t><list style="symbols">
  <t>noPersist: "Boolean" (default: false)
If true, blobs created by this call are ephemeral: they may be
referenced via creation id backreferences within the same JMAP
request, but the server is not required to persist them beyond the
lifetime of the request.  The server <bcp14>MAY</bcp14> omit ephemeral blobs from
the <spanx style="verb">created</spanx> map of the response and from the <spanx style="verb">createdIds</spanx> of the
final Response object if it did not create a referenceable blob.
This allows servers to optimise pipelines where intermediate blobs
are never needed after the request completes.</t>
</list></t>

<t>When this capability is present, Blob/upload also gains the
following additional request properties:</t>

<t><list style="symbols">
  <t>update: "Id[Object]" (default: null)
A map of blobId to an empty object.  No properties may be
set on a blob; the purpose of update is to "touch" the blob,
refreshing its lifetime on the server.  The response includes
an <spanx style="verb">updated</spanx> map of blobId to an object which <bcp14>MAY</bcp14> contain an
<spanx style="verb">expires</spanx> property with the new expiry time.  If the blobId
does not exist, it <bcp14>MUST</bcp14> be reported in a <spanx style="verb">notUpdated</spanx> map
with a <spanx style="verb">notFound</spanx> SetError.</t>
  <t>destroy: "Id[]" (default: null)
An array of blobIds to destroy.  The server <bcp14>MUST</bcp14> reject
any blob that is still referenced by another object with a
<spanx style="verb">blobHasReference</spanx> SetError.  If the blobId does not exist, the
server <bcp14>MUST</bcp14> return a <spanx style="verb">notFound</spanx> SetError.  Successfully
destroyed blobIds are returned in a <spanx style="verb">destroyed</spanx> array.
Failed destroys are returned in a <spanx style="verb">notDestroyed</spanx> map of
blobId to SetError.</t>
</list></t>

</section>
<section anchor="the-expires-response-property"><name>The "expires" response property</name>

<t>When this capability is present, the following blob creation
responses <bcp14>MAY</bcp14> include an additional property: the
resumableUploadUrl response, the Blob/upload response
(<xref target="JMAP-BLOB"/>, Section 4), and the Blob/convert response defined
below.</t>

<t><list style="symbols">
  <t>expires: "UTCDate|null"
A hint from the server indicating the likely availability of
the blob.  The blob is likely to remain available until this
time, and likely not to be available after it.  This is not a
guarantee in either direction: the server <bcp14>MAY</bcp14> garbage collect
the blob before this time if it is unreferenced, and <bcp14>MAY</bcp14>
retain it longer.  If null or absent, the server provides no
hint about the blob's lifetime.</t>
</list></t>

<t>Clients that need the blob to persist beyond the <spanx style="verb">expires</spanx> time
should reference it from a persistent object (e.g., a FileNode
or an Email) before it expires.</t>

</section>
<section anchor="new-method-blobconvert"><name>New method Blob/convert</name>

<t>Blob/convert is defined under the <spanx style="verb">urn:ietf:params:jmap:blobext</spanx>
capability and requires that capability in the request's <spanx style="verb">using</spanx>
array.</t>

<t>Blob/convert performs server-side transformations on blobs.  Like
Blob/upload (<xref target="JMAP-BLOB"/>, Section 4), it takes an <spanx style="verb">accountId</spanx> and a
<spanx style="verb">create</spanx> argument that maps creation ids to conversion request objects.</t>

<t>Each conversion request object <bcp14>MAY</bcp14> also include the following property:</t>

<t><list style="symbols">
  <t>noPersist: "Boolean" (default: false)
If true, the resulting blob is ephemeral: it may be referenced via
creation id backreferences within the same JMAP request, but the
server is not required to persist it beyond the lifetime of the
request.  The server <bcp14>MAY</bcp14> omit ephemeral blobs from the <spanx style="verb">created</spanx>
map of the response and from the <spanx style="verb">createdIds</spanx> of the final Response
object if it did not create a referenceable blob.</t>
</list></t>

<t>Each conversion request object <bcp14>MUST</bcp14> contain exactly one of the
following properties, which determines the type of conversion:</t>

<t><list style="symbols">
  <t>imageConvert: ImageConvertRecipe</t>
  <t>archive: ArchiveRecipe</t>
  <t>unArchive: UnArchiveRecipe</t>
  <t>compress: CompressRecipe</t>
  <t>unCompress: UnCompressRecipe</t>
  <t>delta: DeltaRecipe</t>
  <t>patch: PatchRecipe</t>
</list></t>

<t>The response has the same structure as Blob/upload (<xref target="JMAP-BLOB"/>,
Section 4): a <spanx style="verb">created</spanx> map of creation id to an object containing
<spanx style="verb">id</spanx>, <spanx style="verb">type</spanx>, and <spanx style="verb">size</spanx> for each successful conversion, and a
<spanx style="verb">notCreated</spanx> map of creation id to a SetError object for each failed
conversion.  The <spanx style="verb">id</spanx> is the blobId of the created blob.  The server
<bcp14>MAY</bcp14> also return an <spanx style="verb">expires</spanx> property (see "The expires response
property" above).  Creation id backreferences (using the <spanx style="verb">#</spanx> prefix)
resolve to this <spanx style="verb">id</spanx> and may be used in subsequent conversions within
the same Blob/convert call or in later method calls within the same
JMAP request.</t>

<t>A server <bcp14>MAY</bcp14> return a blobId for a conversion result without
immediately generating the output data.  In this case the server
<bcp14>MUST</bcp14> generate the data when the blob is later accessed (e.g., via
a download request or as input to another operation).  This allows
the server to respond quickly to Blob/convert requests while
deferring expensive work such as image resizing or archive
creation.  The returned blobId <bcp14>MUST</bcp14> be usable in all contexts
where a regular blobId is accepted.  If the deferred generation
later fails (e.g., the source blob has expired), the server
<bcp14>SHOULD</bcp14> return an appropriate HTTP error when the blob is
downloaded.  If the exact size of the output is not yet known, the
server <bcp14>MUST</bcp14> omit the <spanx style="verb">size</spanx> property from the response for that
creation.  If a client later requests the <spanx style="verb">size</spanx> property via
Blob/get for a deferred blob, the server <bcp14>MUST</bcp14> generate the blob
at that point and return the actual size.</t>

<t>The server <bcp14>MUST</bcp14> resolve the order of dependencies between entries
in the <spanx style="verb">create</spanx> map and process them in an order such that all
backreferences are satisfied.  If a dependency cycle is detected,
all members of the cycle <bcp14>MUST</bcp14> be rejected with an
"invalidProperties" error.</t>

<section anchor="imageconvertrecipe"><name>ImageConvertRecipe</name>

<t>An ImageConvertRecipe converts an image blob to a different format
or size.  It is an object with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the source image.</t>
  <t>type: "String"
Media type (<xref target="MEDIA-TYPES"/>) of the image to create (e.g.
"image/png").  <bcp14>MUST</bcp14> be one of the values in the server's
<spanx style="verb">supportedImageTypes</spanx> capability.</t>
  <t>width: "UnsignedInt|null"
Maximum width in pixels of the image to create.  If null, the
server preserves the source width (or scales proportionally if
only <spanx style="verb">height</spanx> is given).</t>
  <t>height: "UnsignedInt|null"
Maximum height in pixels of the image to create.  If null, the
server preserves the source height (or scales proportionally if
only <spanx style="verb">width</spanx> is given).</t>
  <t>ignoreAspect: "Boolean|null"
If true, resize to exactly the given width and height, even if
the aspect ratio is changed.  If null or false, the image is
scaled to fit within the given dimensions while preserving the
aspect ratio.</t>
  <t>quality: "UnsignedInt|null"
Compression quality for lossy formats, as a value from 1 (lowest
quality, smallest file) to 100 (highest quality, largest file).
Only meaningful for formats that support lossy compression such as
image/jpeg and image/webp.  If null, the server selects a sensible
default.</t>
  <t>colorSpace: "String|null"
The color space for the output image.  Defined values are "sRGB"
and "grayscale".  If null, the server preserves the source image's
color space where possible.</t>
  <t>background: "String|null"
A fill color to use when the source image has transparency but the
target format does not support it (e.g. converting PNG to JPEG).
The value is a CSS-style hex color string (e.g. "#ffffff" for white).
If null, the server selects a sensible default (typically white).</t>
  <t>stripMetadata: "Boolean|null"
If true, strip image metadata such as EXIF, XMP, and IPTC data from
the output.  If null or false, the server preserves metadata where
the target format supports it.</t>
  <t>autoOrient: "Boolean|null"
If true, automatically rotate and flip the image according to its
EXIF orientation tag, then reset the tag.  If null or false, the
image data is not reoriented.</t>
</list></t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — the referenced blobId does not exist.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedImageTypes</spanx>, or
the source blob is not a supported image format.</t>
  <t>"tooLarge" — the source blob exceeds <spanx style="verb">maxConvertSize</spanx>, or the
requested dimensions exceed <spanx style="verb">maxImageDimension</spanx>.</t>
</list></t>

</section>
<section anchor="archiverecipe"><name>ArchiveRecipe</name>

<t>An ArchiveRecipe creates an archive blob from a list of entries.
It is an object with the following properties:</t>

<t><list style="symbols">
  <t>type: "String"
The MIME type of the archive to create.  <bcp14>MUST</bcp14> be one of the values
in the server's <spanx style="verb">supportedArchiveTypes</spanx> capability.  Defined values
are "application/zip", "application/x-tar", and "application/x-cpio".</t>
  <t>entries: "ArchiveEntry[]"
An array of ArchiveEntry objects describing the contents of the
archive.</t>
</list></t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — a referenced entry blobId does not exist.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedArchiveTypes</spanx>;
an entry has an unsupported entryType for the archive format; or
a required field (e.g. linkTarget for symlink entries) is missing.</t>
  <t>"tooLarge" — the number of entries exceeds <spanx style="verb">maxArchiveEntries</spanx>,
or a referenced blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

<section anchor="archiveentry"><name>ArchiveEntry</name>

<t>An ArchiveEntry describes a single entry in an archive.  It is used
both as input (in ArchiveRecipe) and as output (in UnArchiveRecipe
results).  It is an object with the following properties:</t>

<t><list style="symbols">
  <t>name: "String"
The path of the entry within the archive.  Directory entries <bcp14>MUST</bcp14>
have a name ending with "/".</t>
  <t>blobId: "BlobId|null"
The blobId of the content for this entry.  <bcp14>MUST</bcp14> be non-null for
file entries.  <bcp14>MUST</bcp14> be null or absent for directory, symlink,
hardlink, fifo, and device entries.  Violating these constraints
is an "invalidProperties" error.</t>
  <t>entryType: "String|null"
The type of the entry.  If null, defaults to "file".  Defined values
are "file" (a regular file, the default), "directory", "symlink"
(a symbolic link), "hardlink" (a hard link), "fifo" (a named pipe),
"blockDevice" (a block device node), and "charDevice" (a character
device node).  The server <bcp14>MUST</bcp14> reject entries with unsupported
types for the chosen archive format with an "invalidProperties"
error.</t>
  <t>modified: "UTCDate|null"
The modification time of the entry as an RFC 3339 timestamp.
If null, defaults to the current server time.</t>
  <t>linkTarget: "String|null"
The target path for symlink and hardlink entries.  <bcp14>MUST</bcp14> be non-null
when entryType is "symlink" or "hardlink".  <bcp14>MUST</bcp14> be null for all
other entry types.</t>
  <t>mode: "String|null"
Unix file permissions as an octal string (e.g. "0755", "0644").
If null, the server chooses a reasonable default.  This is
represented as a string rather than an integer to avoid ambiguity
between octal and decimal interpretation.</t>
  <t>uid: "UnsignedInt|null"
The numeric user ID of the entry owner.</t>
  <t>gid: "UnsignedInt|null"
The numeric group ID of the entry owner.</t>
  <t>ownerName: "String|null"
The user name of the entry owner.</t>
  <t>groupName: "String|null"
The group name of the entry owner.</t>
  <t>devMajor: "UnsignedInt|null"
The major device number for "blockDevice" and "charDevice" entries.</t>
  <t>devMinor: "UnsignedInt|null"
The minor device number for "blockDevice" and "charDevice" entries.</t>
  <t>comment: "String|null"
A comment string for this entry.</t>
  <t>compressionMethod: "String|null"
The per-entry compression method.  Defined values are "store" (no
compression) and "deflate".  If null, the server chooses a
reasonable default.</t>
</list></t>

</section>
<section anchor="considerations-for-applicationzip"><name>Considerations for application/zip</name>

<t>The zip format only supports "file" and "directory" entry types.
The <spanx style="verb">comment</spanx> and <spanx style="verb">compressionMethod</spanx> properties are only meaningful
for zip archives.  The <spanx style="verb">mode</spanx>, <spanx style="verb">uid</spanx>, <spanx style="verb">gid</spanx>, <spanx style="verb">ownerName</spanx>,
<spanx style="verb">groupName</spanx>, <spanx style="verb">devMajor</spanx>, and <spanx style="verb">devMinor</spanx> properties are ignored.</t>

</section>
<section anchor="considerations-for-applicationx-tar"><name>Considerations for application/x-tar</name>

<t>The tar format supports all entry types.  The <spanx style="verb">mode</spanx>, <spanx style="verb">uid</spanx>, <spanx style="verb">gid</spanx>,
<spanx style="verb">ownerName</spanx>, <spanx style="verb">groupName</spanx>, <spanx style="verb">devMajor</spanx>, and <spanx style="verb">devMinor</spanx> properties are
meaningful for tar archives.  The <spanx style="verb">comment</spanx> and <spanx style="verb">compressionMethod</spanx>
properties are ignored.</t>

<t>Tar archives are not inherently compressed.  To create a compressed
tar archive (e.g. a .tar.gz file), first create the tar archive
using ArchiveRecipe, then compress the result using CompressRecipe.
The following example creates a .tar.gz containing three files in a
single Blob/convert call, using a backreference from the archive
creation to the compression step:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "t1": {
      "archive": {
        "type": "application/x-tar",
        "entries": [
          {
            "name": "site/index.html",
            "blobId": "Baaaa",
            "modified": "2026-03-01T12:00:00Z",
            "mode": "0644"
          },
          {
            "name": "site/logo.png",
            "blobId": "Bbbbb",
            "modified": "2026-02-15T09:30:00Z",
            "mode": "0644"
          },
          {
            "name": "site/style.css",
            "blobId": "Bcccc",
            "modified": "2026-03-01T12:00:00Z",
            "mode": "0644"
          }
        ]
      }
    },
    "t2": {
      "compress": {
        "blobId": "#t1",
        "type": "application/gzip"
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

</section>
<section anchor="considerations-for-applicationx-cpio"><name>Considerations for application/x-cpio</name>

<t>The cpio format supports all entry types except that <spanx style="verb">ownerName</spanx> and
<spanx style="verb">groupName</spanx> are not supported.  The <spanx style="verb">comment</spanx> and
<spanx style="verb">compressionMethod</spanx> properties are ignored.</t>

</section>
</section>
<section anchor="unarchiverecipe"><name>UnArchiveRecipe</name>

<t>An UnArchiveRecipe extracts the entry listing from an existing archive
blob.  It is an object with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the archive to extract.</t>
  <t>type: "String|null"
The MIME type of the archive format.  If null, the server <bcp14>SHOULD</bcp14>
attempt to auto-detect the format from the blob content (e.g. by
inspecting magic bytes).  If auto-detection fails, the server <bcp14>MUST</bcp14>
return an "unknownFormat" error.</t>
</list></t>

<t>In addition to the standard creation response properties, a
successful UnArchiveRecipe result includes:</t>

<t><list style="symbols">
  <t>entries: "ArchiveEntry[]"
An array of ArchiveEntry objects describing the contents of the
archive.  Each file entry will have a blobId that can be used to
access the content of that entry.</t>
</list></t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — the referenced blobId does not exist.</t>
  <t>"unknownFormat" — the server could not determine or does not support
the archive format.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedArchiveTypes</spanx>.</t>
  <t>"tooLarge" — the source blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

</section>
<section anchor="compressrecipe"><name>CompressRecipe</name>

<t>A CompressRecipe compresses a blob using a specified compression
algorithm.  It is an object with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the data to compress.</t>
  <t>type: "String"
The MIME type of the compression format to use.  <bcp14>MUST</bcp14> be one of the
values in the server's <spanx style="verb">supportedCompressionTypes</spanx> capability.
Defined values are "application/gzip", "application/x-bzip2",
"application/x-xz", and "application/zstd".</t>
  <t>level: "UnsignedInt|null"
The compression level, where higher values produce smaller output
at the cost of more CPU time.  If null, the server uses the
format's default level.  The valid range depends on the format;
if the requested level is outside the valid range, the server
<bcp14>SHOULD</bcp14> use the nearest valid value.</t>
  <t>checksum: "Boolean|null"
If true, include an integrity checksum in the compressed output.
If null, the server uses the format's default behaviour.</t>
</list></t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — the referenced blobId does not exist.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedCompressionTypes</spanx>.</t>
  <t>"tooLarge" — the source blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

<section anchor="considerations-for-applicationgzip"><name>Considerations for application/gzip</name>

<t>Compression level ranges from 1 (fastest) to 9 (best compression).
The default is typically 6.  Gzip always includes a CRC-32 checksum;
the <spanx style="verb">checksum</spanx> property is ignored.</t>

</section>
<section anchor="considerations-for-applicationx-bzip2"><name>Considerations for application/x-bzip2</name>

<t>Compression level ranges from 1 (fastest, 100k block size) to 9
(best compression, 900k block size).  The default is typically 9.
Bzip2 always includes a CRC-32 checksum; the <spanx style="verb">checksum</spanx> property is
ignored.</t>

</section>
<section anchor="considerations-for-applicationx-xz"><name>Considerations for application/x-xz</name>

<t>Compression level ranges from 0 (fastest) to 9 (best compression).
The default is typically 6.  Xz always includes an integrity check;
if <spanx style="verb">checksum</spanx> is true the server <bcp14>SHOULD</bcp14> use SHA-256, otherwise CRC-64
is used by default.</t>

</section>
<section anchor="considerations-for-applicationzstd"><name>Considerations for application/zstd</name>

<t>Compression level ranges from 1 (fastest) to 22 (best compression).
The default is typically 3.  If <spanx style="verb">checksum</spanx> is true, an xxHash-64
checksum is included in the frame; the default is false.</t>

</section>
</section>
<section anchor="uncompressrecipe"><name>UnCompressRecipe</name>

<t>An UnCompressRecipe decompresses a compressed blob.  It is an object
with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the compressed data to decompress.</t>
  <t>type: "String|null"
The MIME type of the compression format.  If null, the server <bcp14>SHOULD</bcp14>
attempt to auto-detect the format from magic bytes.  If auto-detection
fails, the server <bcp14>MUST</bcp14> return an "unknownFormat" error.</t>
</list></t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — the referenced blobId does not exist.</t>
  <t>"unknownFormat" — the server could not determine or does not support
the compression format.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedCompressionTypes</spanx>.</t>
  <t>"tooLarge" — the source blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

</section>
<section anchor="deltarecipe"><name>DeltaRecipe</name>

<t>A DeltaRecipe computes a delta between two blobs.  It is an object
with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the original (base) blob.</t>
  <t>newBlobId: "BlobId"
The blobId of the new blob to compare against.</t>
  <t>type: "String"
The media type of the delta format to produce.  <bcp14>MUST</bcp14> be one of the
values in the server's <spanx style="verb">supportedPatchTypes</spanx> capability.</t>
</list></t>

<t>The result blob is the computed delta, which can be applied to the
base blob using PatchRecipe to reconstruct the new blob.</t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — a referenced blobId does not exist.</t>
  <t>"invalidProperties" — the type is not in <spanx style="verb">supportedPatchTypes</spanx>.</t>
  <t>"tooLarge" — a referenced blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

<section anchor="considerations-for-applicationx-rdiff-delta"><name>Considerations for application/x-rdiff-delta</name>

<t>The server computes an rdiff signature of the base blob and then
generates a delta against the new blob.  The resulting delta blob
can only be applied to the exact base blob used to generate it.</t>

</section>
<section anchor="considerations-for-applicationx-bsdiff"><name>Considerations for application/x-bsdiff</name>

<t>The server produces a bsdiff-format patch.  Both blobs must fit in
memory; servers <bcp14>MAY</bcp14> reject very large blobs with a "tooLarge" error.</t>

</section>
<section anchor="considerations-for-textx-diff"><name>Considerations for text/x-diff</name>

<t>The server produces a unified diff.  Both blobs are interpreted as
text.  If either blob contains content that cannot be interpreted as
text, the server <bcp14>MUST</bcp14> return an "unknownFormat" error.</t>

</section>
</section>
<section anchor="patchrecipe"><name>PatchRecipe</name>

<t>A PatchRecipe applies a delta to a base blob to produce a new blob.
It is an object with the following properties:</t>

<t><list style="symbols">
  <t>blobId: "BlobId"
The blobId of the base blob to patch.</t>
  <t>deltaBlobId: "BlobId"
The blobId of the delta to apply.</t>
  <t>deltaType: "String"
The media type of the delta format.  <bcp14>MUST</bcp14> be one of the values in
the server's <spanx style="verb">supportedPatchTypes</spanx> capability.</t>
</list></t>

<t>The result blob is the patched output.</t>

<t>Errors:</t>

<t><list style="symbols">
  <t>"notFound" — a referenced blobId does not exist.</t>
  <t>"invalidProperties" — the deltaType is not in <spanx style="verb">supportedPatchTypes</spanx>.</t>
  <t>"unknownFormat" — the delta blob is not valid for the specified
format (e.g., corrupt or malformed delta data).</t>
  <t>"tooLarge" — a referenced blob exceeds <spanx style="verb">maxConvertSize</spanx>.</t>
</list></t>

</section>
</section>
</section>
<section anchor="examples"><name>Examples</name>

<section anchor="querying-blob-chunks"><name>Querying Blob Chunks</name>

<t>This example fetches a blob's chunk structure with offsets, sizes,
and SHA-256 digests:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/get", {
  "accountId": "abc",
  "ids": ["B1a2b3c"],
  "dataSourceProperties": [
    "blobId", "size", "offset", "length", "position",
    "digest:sha-256"
  ]
}, "0"]]
]]></sourcecode></figure>

<t>The response shows the blob is stored as two chunks:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/get", {
  "accountId": "abc",
  "list": [{
    "id": "B1a2b3c",
    "size": 10485760,
    "chunks": [
      {
        "blobId": "Bchunk1",
        "size": 5242880,
        "offset": 0,
        "length": 5242880,
        "position": 0,
        "digest:sha-256": "a1b2c3..."
      },
      {
        "blobId": "Bchunk2",
        "size": 5242880,
        "offset": 0,
        "length": 5242880,
        "position": 5242880,
        "digest:sha-256": "d4e5f6..."
      }
    ]
  }],
  "notFound": []
}, "0"]]
]]></sourcecode></figure>

<t>The <spanx style="verb">position</spanx> values show where each chunk fits in the assembled
blob, and the <spanx style="verb">digest:sha-256</spanx> values can be used to verify chunk
integrity.</t>

</section>
<section anchor="creating-a-zip-archive"><name>Creating a Zip Archive</name>

<t>This example creates a zip file containing an HTML document, a CSS
file, and a JPEG image:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "z1": {
      "archive": {
        "type": "application/zip",
        "entries": [
          {
            "name": "site/index.html",
            "blobId": "Baaaa"
          },
          {
            "name": "site/style.css",
            "blobId": "Bbbbb"
          },
          {
            "name": "site/photo.jpg",
            "blobId": "Bcccc"
          }
        ]
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

<t>The response includes the blobId, type, and size of the created
archive:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "created": {
    "z1": {
      "id": "B9f2a4e",
      "type": "application/zip",
      "size": 104857
    }
  },
  "notCreated": {}
}, "0"]]
]]></sourcecode></figure>

</section>
<section anchor="creating-a-compressed-tar-archive"><name>Creating a Compressed Tar Archive</name>

<t>This example creates a .tar.gz file from the same three files.
The intermediate tar blob uses <spanx style="verb">noPersist</spanx> since only the final
compressed result is needed:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "t1": {
      "noPersist": true,
      "archive": {
        "type": "application/x-tar",
        "entries": [
          {
            "name": "site/index.html",
            "blobId": "Baaaa",
            "modified": "2026-03-01T12:00:00Z",
            "mode": "0644"
          },
          {
            "name": "site/style.css",
            "blobId": "Bbbbb",
            "modified": "2026-03-01T12:00:00Z",
            "mode": "0644"
          },
          {
            "name": "site/photo.jpg",
            "blobId": "Bcccc",
            "modified": "2026-02-15T09:30:00Z",
            "mode": "0644"
          }
        ]
      }
    },
    "t2": {
      "compress": {
        "blobId": "#t1",
        "type": "application/gzip"
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

<t>Because "t1" was created with <spanx style="verb">noPersist</spanx>, the server may omit it
from the response:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "created": {
    "t2": {
      "id": "Bd81c7f",
      "type": "application/gzip",
      "size": 98304
    }
  },
  "notCreated": {}
}, "0"]]
]]></sourcecode></figure>

</section>
<section anchor="extracting-a-compressed-tar-archive"><name>Extracting a Compressed Tar Archive</name>

<t>This example decompresses and extracts a .tar.gz file to discover
its contents.  The intermediate decompressed tar blob uses
<spanx style="verb">noPersist</spanx>:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "u1": {
      "noPersist": true,
      "unCompress": {
        "blobId": "Bd81c7f",
        "type": "application/gzip"
      }
    },
    "u2": {
      "unArchive": {
        "blobId": "#u1",
        "type": "application/x-tar"
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

<t>The response for the UnArchiveRecipe includes the standard creation
response properties plus an <spanx style="verb">entries</spanx> array listing the archive
contents, with a blobId for each file entry:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "created": {
    "u2": {
      "id": "Be3a901",
      "type": "application/x-tar",
      "size": 102400,
      "entries": [
        {
          "name": "site/index.html",
          "blobId": "Bdd001",
          "entryType": "file",
          "modified": "2026-03-01T12:00:00Z",
          "mode": "0644"
        },
        {
          "name": "site/style.css",
          "blobId": "Bdd002",
          "entryType": "file",
          "modified": "2026-03-01T12:00:00Z",
          "mode": "0644"
        },
        {
          "name": "site/photo.jpg",
          "blobId": "Bdd003",
          "entryType": "file",
          "modified": "2026-02-15T09:30:00Z",
          "mode": "0644"
        }
      ]
    }
  },
  "notCreated": {}
}, "0"]]
]]></sourcecode></figure>

<t>The returned blobIds ("Bdd001", "Bdd002", "Bdd003") can be used
to download individual files or as inputs to further Blob/convert
operations.</t>

</section>
<section anchor="computing-and-applying-a-delta"><name>Computing and Applying a Delta</name>

<t>This example computes a unified diff between two versions of a
text file:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "d1": {
      "delta": {
        "blobId": "BoldVersion",
        "newBlobId": "BnewVersion",
        "type": "text/x-diff"
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

<t>The response contains the delta blob:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "created": {
    "d1": {
      "id": "Bdelta789",
      "type": "text/x-diff",
      "size": 1234
    }
  },
  "notCreated": {}
}, "0"]]
]]></sourcecode></figure>

<t>The delta can later be applied to the original blob to reconstruct
the new version:</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "create": {
    "p1": {
      "patch": {
        "blobId": "BoldVersion",
        "deltaBlobId": "Bdelta789",
        "deltaType": "text/x-diff"
      }
    }
  }
}, "0"]]
]]></sourcecode></figure>

<t>The result is a blob identical to "BnewVersion":</t>

<figure><sourcecode type="json"><![CDATA[
[["Blob/convert", {
  "accountId": "abc",
  "created": {
    "p1": {
      "id": "Breconstructed",
      "type": "application/octet-stream",
      "size": 48576
    }
  },
  "notCreated": {}
}, "0"]]
]]></sourcecode></figure>

</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<t>All security considerations from <xref target="JMAP-CORE"/> and <xref target="JMAP-BLOB"/> apply
to this document.</t>

<section anchor="resource-consumption"><name>Resource Consumption</name>

<t>Several operations defined in this document can consume significant
server resources.</t>

<t>Archive and compression operations may require substantial CPU and
memory.  Servers <bcp14>SHOULD</bcp14> impose reasonable limits on archive size,
number of entries, nesting depth of archives within archives,
compression ratios (to mitigate zip bomb attacks), and total
processing time.  Servers <bcp14>SHOULD</bcp14> reject requests that would exceed
these limits with a "tooLarge" or "serverFail" error as appropriate.</t>

<t>Image conversion can also consume significant resources, especially
for very large images or high output dimensions.</t>

<t>Delta and patch operations can also be resource-intensive,
particularly for large blobs.  Servers <bcp14>SHOULD</bcp14> impose limits on the
size of blobs that can be used as inputs to these operations.</t>

<t>Servers <bcp14>SHOULD</bcp14> advertise their limits via the <spanx style="verb">maxConvertSize</spanx>,
<spanx style="verb">maxArchiveEntries</spanx>, and <spanx style="verb">maxImageDimension</spanx> capability properties
so that clients can avoid making requests that will be rejected.
Even when these properties are not advertised, servers <bcp14>SHOULD</bcp14> set
sensible internal limits and reject requests that exceed them.</t>

</section>
<section anchor="archive-path-traversal"><name>Archive Path Traversal</name>

<t>Archive formats allow entry names containing path separators and
relative path components such as "../".  Malicious archives may use
names like "../../etc/passwd" to attempt directory traversal.  While
UnArchiveRecipe only returns entry metadata and blob references
(not files on the server filesystem), clients that extract archive
contents to a filesystem <bcp14>MUST</bcp14> validate entry names and reject or
sanitize paths containing ".." components or absolute paths.
Servers <bcp14>SHOULD</bcp14> reject ArchiveRecipe requests containing entry names
with ".." path components.</t>

</section>
<section anchor="content-smuggling"><name>Content Smuggling</name>

<t>The ability to split content into multiple blobs, recombine them via
Blob/upload, and apply delta patches may be used to bypass security
scanners that inspect blob content.  Servers that perform content
scanning <bcp14>SHOULD</bcp14> scan the output of Blob/convert operations as well
as the inputs.</t>

</section>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<section anchor="jmap-capability-registration-for-urnietfparamsjmapblobext"><name>JMAP Capability Registration for urn:ietf:params:jmap:blobext</name>

<t>IANA is requested to register the "Blob Extended" Capability as follows:</t>

<t>Capability Name: urn:ietf:params:jmap:blobext</t>

<t>Intended use: common</t>

<t>Change Controller: IETF</t>

<t>Specification document: this document</t>

<t>Security and privacy considerations: this document, Security Considerations</t>

</section>
<section anchor="jmap-error-code-registrations"><name>JMAP Error Code Registrations</name>

<t>IANA is requested to register the following entries in the "JMAP
Error Codes" registry:</t>

<section anchor="unknownformat"><name>unknownFormat</name>

<t>JMAP Error Code: unknownFormat</t>

<t>Intended use: common</t>

<t>Change Controller: IETF</t>

<t>Description: The server could not determine the format of the blob,
or the detected format is not supported.  This error is returned
when auto-detection of archive or compression format fails, or when
the blob content does not match the specified format.</t>

<t>Reference: this document</t>

</section>
<section anchor="blobhasreference"><name>blobHasReference</name>

<t>JMAP Error Code: blobHasReference</t>

<t>Intended use: common</t>

<t>Change Controller: IETF</t>

<t>Description: The blob cannot be destroyed because it is still
referenced by one or more objects.  The client can use Blob/lookup
(<xref target="JMAP-BLOB"/>, Section 5) to discover which objects reference
the blob.</t>

<t>Reference: this document</t>

</section>
</section>
</section>
<section anchor="changes"><name>Changes</name>

<t>EDITOR: please remove this section before publication.</t>

<t>The source of this document exists on github at: https://github.com/brong/draft-gondwana-jmap-blobext/</t>

<t><strong>draft-gondwana-jmap-blobext-03</strong></t>

<t><list style="symbols">
  <t>Added update (touch) and destroy operations to Blob/upload.</t>
</list></t>

<t><strong>draft-gondwana-jmap-blobext-02</strong></t>

<t><list style="symbols">
  <t>Replaced RdiffRecipe with generic DeltaRecipe and PatchRecipe using
media types (rdiff, bsdiff, unified diff).</t>
  <t>Replaced supportsRdiff with supportedPatchTypes capability.</t>
  <t>Clarified chunkSize as a hint, not a definitive statement.</t>
  <t>Added lazy generation text for Blob/convert (deferred output).</t>
  <t>Defined "expires" response property for blob creation responses.</t>
</list></t>

<t><strong>draft-gondwana-jmap-blobext-01</strong></t>

<t><list style="symbols">
  <t>Added Blob/convert method with recipes for image conversion, archiving,
compression, and rdiff.</t>
  <t>Added noPersist option to Blob/upload and Blob/convert for ephemeral
intermediate blobs in pipelines.</t>
  <t>Removed rdiffSignature and rdiffPatch from Blob/get and DataSourceObject.</t>
  <t>Fleshed out capability object with supported type lists.</t>
  <t>Added capability and method examples.</t>
  <t>Expanded Security Considerations.</t>
  <t>Updated IANA registrations with error codes and corrected capability URI.</t>
  <t>Added limit capability properties: maxConvertSize, maxArchiveEntries,
maxImageDimension, and supportsRdiff.</t>
  <t>Added dependency resolution requirement for Blob/convert create map
with cycle detection.</t>
  <t>Now updates both RFC 8620 and RFC 9404.</t>
</list></t>

<t><strong>draft-gondwana-jmap-blobext-00</strong></t>

<t><list style="symbols">
  <t>initial proposal</t>
</list></t>

</section>
<section anchor="acknowledgements"><name>Acknowledgements</name>

<t>TODO</t>

<t>{backmatter}</t>

</section>


  </middle>

  <back>



    <references title='Normative References' anchor="sec-normative-references">



<reference anchor="URI-TEMPLATE">
  <front>
    <title>URI Template</title>
    <author fullname="J. Gregorio" initials="J." surname="Gregorio"/>
    <author fullname="R. Fielding" initials="R." surname="Fielding"/>
    <author fullname="M. Hadley" initials="M." surname="Hadley"/>
    <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
    <author fullname="D. Orchard" initials="D." surname="Orchard"/>
    <date month="March" year="2012"/>
    <abstract>
      <t>A URI Template is a compact sequence of characters for describing a range of Uniform Resource Identifiers through variable expansion. This specification defines the URI Template syntax and the process for expanding a URI Template into a URI reference, along with guidelines for the use of URI Templates on the Internet. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="6570"/>
  <seriesInfo name="DOI" value="10.17487/RFC6570"/>
</reference>

<reference anchor="JMAP-CORE">
  <front>
    <title>The JSON Meta Application Protocol (JMAP)</title>
    <author fullname="N. Jenkins" initials="N." surname="Jenkins"/>
    <author fullname="C. Newman" initials="C." surname="Newman"/>
    <date month="July" year="2019"/>
    <abstract>
      <t>This document specifies a protocol for clients to efficiently query, fetch, and modify JSON-based data objects, with support for push notification of changes and fast resynchronisation and for out-of- band binary data upload/download.</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="8620"/>
  <seriesInfo name="DOI" value="10.17487/RFC8620"/>
</reference>

<reference anchor="JMAP-BLOB">
  <front>
    <title>JSON Meta Application Protocol (JMAP) Blob Management Extension</title>
    <author fullname="B. Gondwana" initials="B." role="editor" surname="Gondwana"/>
    <date month="August" year="2023"/>
    <abstract>
      <t>The JSON Meta Application Protocol (JMAP) base protocol (RFC 8620) provides the ability to upload and download arbitrary binary data via HTTP POST and GET on a defined endpoint. This binary data is called a "blob".</t>
      <t>This extension adds additional ways to create and access blobs by making inline method calls within a standard JMAP request.</t>
      <t>This extension also adds a reverse lookup mechanism to discover where blobs are referenced within other data types.</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="9404"/>
  <seriesInfo name="DOI" value="10.17487/RFC9404"/>
</reference>

<reference anchor="MEDIA-TYPES">
  <front>
    <title>Media Type Specifications and Registration Procedures</title>
    <author fullname="N. Freed" initials="N." surname="Freed"/>
    <author fullname="J. Klensin" initials="J." surname="Klensin"/>
    <author fullname="T. Hansen" initials="T." surname="Hansen"/>
    <date month="January" year="2013"/>
    <abstract>
      <t>This document defines procedures for the specification and registration of media types for use in HTTP, MIME, and other Internet protocols. This memo documents an Internet Best Current Practice.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="13"/>
  <seriesInfo name="RFC" value="6838"/>
  <seriesInfo name="DOI" value="10.17487/RFC6838"/>
</reference>


<reference anchor="HTTP-RESUMABLE-UPLOADS">
   <front>
      <title>Resumable Uploads for HTTP</title>
      <author fullname="Marius Kleidl" initials="M." surname="Kleidl">
         <organization>Transloadit</organization>
      </author>
      <author fullname="Guoye Zhang" initials="G." surname="Zhang">
         <organization>Apple Inc.</organization>
      </author>
      <author fullname="Lucas Pardue" initials="L." surname="Pardue">
         <organization>Cloudflare</organization>
      </author>
      <date day="2" month="March" year="2026"/>
      <abstract>
	 <t>   HTTP data transfers can encounter interruption due to reasons such as
   canceled requests or dropped connections.  If the intended recipient
   can indicate how much of the data was received prior to interruption,
   a sender can resume data transfer at that point instead of attempting
   to transfer all of the data again.  HTTP range requests support this
   concept of resumable downloads from server to client.  This document
   describes a mechanism that supports resumable uploads from client to
   server using HTTP.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-ietf-httpbis-resumable-upload-11"/>
   
</reference>

<reference anchor="RFC2119">
  <front>
    <title>Key words for use in RFCs to Indicate Requirement Levels</title>
    <author fullname="S. Bradner" initials="S." surname="Bradner"/>
    <date month="March" year="1997"/>
    <abstract>
      <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="2119"/>
  <seriesInfo name="DOI" value="10.17487/RFC2119"/>
</reference>

<reference anchor="RFC8174">
  <front>
    <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
    <author fullname="B. Leiba" initials="B." surname="Leiba"/>
    <date month="May" year="2017"/>
    <abstract>
      <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="8174"/>
  <seriesInfo name="DOI" value="10.17487/RFC8174"/>
</reference>




    </references>





  </back>

<!-- ##markdown-source:
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
ilmi4VV+Dv4fP5s1qEybAAA=

-->

</rfc>

