Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion dlcs-docs-client/p02_registering/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from settings import docs_space_id, docs_space_name


# Not yet supported. Returns HTTP 405 Method Not Allowed
# INTENTIONAL error demo - this sample is *supposed* to fail.
# Direct POST of a single asset to a space is not supported; the platform
# returns HTTP 405 Method Not Allowed. Register assets with PUT, or POST a
# collection to the queue instead (see registering-assets).
def post_asset():
space = docs_space_id
ensure_space(space, docs_space_name)
Expand Down
5 changes: 4 additions & 1 deletion dlcs-docs-client/p06_space/space_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def get_images_with_query():
print()


# Not yet supported. Returns HTTP 405 Method Not Allowed
# INTENTIONAL error demo - this sample is *supposed* to fail.
# Direct POST of a single asset to a space is not supported; the platform
# returns HTTP 405 Method Not Allowed. Register assets with PUT, or POST a
# collection to the queue instead (see registering-assets).
def post_asset():
ensure_space(docs_space_id, docs_space_name)
asset = {
Expand Down
14 changes: 13 additions & 1 deletion dlcs-docs-client/p08_queue/post_to_priority_queue.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import settings
from iiif_cs import post_resource, pprint
from iiif_cs import get_cloud_services_resource, post_resource, pprint
from p06_space.ensure_space import ensure_space
from settings import docs_space_id, docs_space_name


def get_priority_queue():
"""GET the priority queue - a CustomerQueue resource with its own counts."""
path = f"/customers/{settings.IIIF_CS_CUSTOMER_ID}/queue/priority"
r = get_cloud_services_resource(path)
print("GET Priority Queue returned:")
queue = r.json()
pprint(queue)
print()
return queue


def post_to_priority_queue():
"""POST a collection of assets to the priority queue for faster processing."""
ensure_space(docs_space_id, docs_space_name)
Expand All @@ -30,4 +41,5 @@ def post_to_priority_queue():


if __name__ == '__main__':
get_priority_queue()
post_to_priority_queue()
57 changes: 0 additions & 57 deletions dlcs-docs-client/p12_origin_strategies/update_credentials.py

This file was deleted.

2 changes: 1 addition & 1 deletion scratch/api-doc/asset-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ These examples belong in the `### Query object` section once supported:
?q={"id":"PHOTO.2.22.36.2.tif"}
```

# Ordering — ⟳ IMPLEMENTED, restore (verified 2026-08-03, DIS-01) — **restore-candidate**
# Ordering — ✅ PROMOTED 2026-08-06 (session 0, DIS-01 ruling): `### Ordering` section restored to asset-queries.mdx with default = `created`. Kept below for the DIS-06 nuance (no field whitelist; unknown field → handled Hydra 500 not 400) which is NOT yet documented — that's DIS-06's call.

You can order by the value of a field of an asset:

Expand Down
10 changes: 10 additions & 0 deletions scratch/api-doc/queues.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,13 @@ release-gated; fix them with the same wording when the adjunct queue ships.

**Disposition: probably-drop** (superseded by code reality). Restore only if batch
activation ever becomes start-of-processing rather than submission.

## XC-12 ruling — batch upsert status semantics (for the adjunct-queue docs when released)

Session 0 (2026-08-06) ruled: the status describes the AGGREGATE outcome of the
request, not itemised per-member results — 201 only when every member was newly
created (RFC 9110 permits 201 for "one or more new resources"), 200 when any member
updated existing state. A 201 therefore always means everything in the request is
new. When the adjunct-queue sections are promoted (PRO-08 release gate), state this
on the queue POST rows using the same wording as adjuncts.mdx "Registering multiple
adjuncts".
21 changes: 20 additions & 1 deletion scratch/api-doc/single-asset-manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,23 @@ The behaviour for file-only assets (placeholder image, `placeholder` and `origin

removed from copy:

In addition to the above, the single asset manifest has an extension property `dlcs:channelOutputs`: an array of content resources and services, one per delivery channel output, each including the channel it belongs to. This is more consistent in structure than the regular manifest properties and can be used for quick programmatic access to channel outputs.
In addition to the above, the single asset manifest has an extension property `dlcs:channelOutputs`: an array of content resources and services, one per delivery channel output, each including the channel it belongs to. This is more consistent in structure than the regular manifest properties and can be used for quick programmatic access to channel outputs.
## Replaced prose preserved (DIS-25, session 0, 2026-08-06)

Original iiif-av bullet (single-asset-manifest.mdx:27), replaced per the DIS-25 ruling:

> For the `iiif-av` delivery channel, the body of the painting annotation is a `Choice` resource listing all the transcoded outputs.

And the audio-example prose:

> The painting body is a `Choice` wrapping the single transcoded output.

**Why changed:** ManifestV3Builder.HandleTimebasedAsset uses a bare `Sound`/`Video`
body when `transcodes.Length == 1` and `PaintingChoice` only for several; an asset
with no transcode metadata gets no canvas at all. The old doc's own "(?)" question
is answered by the code in the opposite direction. The audio example's `Choice`
wrapper was removed and its annotation id corrected to `.../page/image` (the
builder uses `{canvasId}/page/image` for timebased assets too).

**Disposition: probably-drop** (superseded by code reality). Restore only if
always-Choice is ever made the contract (the room chose not to).
2 changes: 2 additions & 0 deletions src/src/content/docs/api-doc/adjuncts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ POST https://api.dlcs.example/customers/2/spaces/5/images/b2921371x_0001.jp2/adj
]
```

The response status code describes the aggregate outcome of the request — per-member results are not itemised. A multi-adjunct POST returns `201 Created` when every member was newly created, and `200 OK` when any member updated an existing adjunct; a `201` from this endpoint therefore always means everything in the request is new. (This follows [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#section-15.3.2), which defines `201` as a request that resulted in "one or more new resources" being created.)

If an adjunct needs to be access-controlled, it specifies [roles](../asset#roles) in the same way assets do, and the platform will emit IIIF Auth services when referencing the adjunct in a manifest.

<Aside type="caution">
Expand Down
13 changes: 12 additions & 1 deletion src/src/content/docs/api-doc/asset-queries.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ sidebar:
import { Aside, LinkCard } from '@astrojs/starlight/components';

<Aside type="caution">
These features are still under development. Queries based on `string1`, `string2`, `string3`, `number1`, `number2` and `number3` are supported. `tags`, `roles`, `id` queries, ordering, `include` and multiple values are not yet supported.
These features are still under development. Queries based on `string1`, `string2`, `string3`, `number1`, `number2` and `number3` are supported, as are [ordering](#ordering) and [include](#include-children). `tags`, `roles`, `id` queries and multiple values are not yet supported.
</Aside>

Any hyperlink to a collection of assets can accept query parameters that filter the returned assets.
Expand Down Expand Up @@ -47,6 +47,17 @@ Only the 6 built-in string and number fields are supported.
?q={"string1":"my-value","number1":99}&pageSize=10&page=2
```

### Ordering

You can order results by the value of a field of an asset:

```
?orderBy=height
?orderByDescending=width
```

The field can be one of the metadata shortcut names above (`string1`, `number2`, ...) or any asset property (e.g., `width`, `height`, `created`). If no ordering is provided, results are ordered by `created`.

### Include Children

The only accepted value is `adjuncts`.
Expand Down
2 changes: 1 addition & 1 deletion src/src/content/docs/api-doc/asset.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ text/plain

## space

The integer identifier of the customer Space. This is readonly on an asset except when sent in a batch to the queue (see [registering assets](../registering-assets)), where a single batch of assets may be intended for different spaces. That is, you can set it on an asset that has yet to be given an `@id` within the system. After this point the value of `space` will always match the space part of the [asset identifier](../identifiers#assetidentifiers). You do not need to supply it on API operations other than creation of assets to the queue, but if you do, it must match the expected space from the asset ID.
The integer identifier of the customer Space. This is readonly on an asset except when sent in a batch to the queue (see [registering assets](../registering-assets)), where a single batch of assets may be intended for different spaces. That is, you can set it on an asset that has yet to be given an `@id` within the system. After this point the value of `space` will always match the space part of the [asset identifier](../identifiers#asset-identifiers). You do not need to supply it on API operations other than creation of assets to the queue, but if you do, it must match the expected space from the asset ID.

| domain | range | readonly | writeonly |
|:---|:---|:---|:---|
Expand Down
12 changes: 9 additions & 3 deletions src/src/content/docs/api-doc/batch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ Old batches are kept on the platform for at least a year but are eventually arch
"superseded": false,
"images": "https://api.dlcs.example/customers/2/queue/batches/875629/images",
"assets": "https://api.dlcs.example/customers/2/queue/batches/875629/assets",
"completedImages": "https://api.dlcs.example/customers/2/queue/batches/875629/completedImages",
"errorImages": "https://api.dlcs.example/customers/2/queue/batches/875629/errorImages",
"test": "https://api.dlcs.example/customers/2/queue/batches/875629/test"
}
```
Expand Down Expand Up @@ -153,7 +151,15 @@ An HTTP POST to this resource will update the batch's [superseded](#superseded)

| Method | Label | Expects | Returns | Status |
|:---|:---|:---|:---|:---|
| POST | Force an update of the batch.superseded property. | - | JSON object with single success property (boolean). | 200 OK |
| POST | Force an update of the batch.superseded property. | - | JSON object with single success property (boolean). | 200 OK, 404 Not Found |

The response body is a plain JSON object, not a Hydra resource — a deliberate exception for this action endpoint:

```json
{ "success": true }
```

`success` is `true` when the test resulted in an update to the batch (marking it superseded and/or finished), and `false` when the batch was tested but no changes were needed. Either way the test itself succeeded — `false` is not an error.

## Adjunct Batch

Expand Down
2 changes: 1 addition & 1 deletion src/src/content/docs/api-doc/custom-headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ A `CustomHeader` resource is created by POSTing to the [customer.customHeaders](
| Method | Label | Expects | Returns | Status |
|:---|:---|:---|:---|:---|
| GET | Retrieve a custom header | - | vocab:CustomHeader | 200 OK, 404 Not Found |
| PUT | Update a custom header | vocab:CustomHeader | vocab:CustomHeader | 200 OK, 400 Bad Request |
| PUT | Update a custom header | vocab:CustomHeader | vocab:CustomHeader | 200 OK, 400 Bad Request, 404 Not Found |
| DELETE | Delete a custom header | - | - | 204 No Content, 404 Not Found |

<Aside type="note">
Expand Down
2 changes: 2 additions & 0 deletions src/src/content/docs/api-doc/customer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,8 @@ Api keys allocated to this customer. The accompanying secret is only available a
| POST | Create a new key | - | vocab:Key (with secret, once) | 200 OK |
| DELETE | Delete an individual key, at `/customers/{customer}/keys/{key}` | - | - | 204 No Content, 400 Bad request |

The POST here is a deliberate exception to the platform's usual convention that a create returns `201 Created`: it is an _action_ returning a one-time payload — the key and its secret — rather than the creation of a resource you can fetch again, so it returns `200 OK`. The secret is never available at any URL afterwards.

The returned collection has `vocab:key` members like this:

```
Expand Down
10 changes: 7 additions & 3 deletions src/src/content/docs/api-doc/identifiers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ The model `id` of an asset must be unique within its space. Unlike other resourc

You are free to use any string as an asset `id`, but it will appear in URLs so it should be URL-safe. Common choices are filenames (with or without the extension), or opaque identifiers like shelfmarks or catalogue references.

## Resources that use `name` instead of `id`
## The identifier exception register

Most resources follow the convention above, where the `id` property holds the model identifier and becomes the last path element of the `@id`. However, some resources use a `name` property for this purpose instead. The notable example is `DeliveryChannelPolicy` (where `name` becomes the last segment of `/customers/{customer}/deliveryChannelPolicies/{channel}/{name}`). (Note: `NamedQuery` also has a `name` property, but unlike `DeliveryChannelPolicy` it is addressed by a minted `id`, not its `name`.)
Resources are addressed by `id`, following the convention above — unless they are listed here. This section is the authoritative register of exceptions: any new resource addressed by something other than `id` must be added to this register in the same pull request that introduces it.

The behaviour is the same as for `id` elsewhere: the value you supply becomes a permanent part of the resource's URI, you choose it yourself, and it must be unique within its parent collection. When creating a `DeliveryChannelPolicy` via PUT the `name` is taken from the URL path rather than the request body; when creating via POST to the parent collection the `name` must be present in the body.
There are exactly two registered exceptions:

1. **`DeliveryChannelPolicy` is addressed by `name`.** Its `name` becomes the last segment of `/customers/{customer}/deliveryChannelPolicies/{channel}/{name}`. The behaviour is the same as for `id` elsewhere: the value you supply becomes a permanent part of the resource's URI, you choose it yourself, and it must be unique within its parent collection. When creating a `DeliveryChannelPolicy` via PUT the `name` is taken from the URL path rather than the request body; when creating via POST to the parent collection the `name` must be present in the body.

2. **`NamedQuery` has a human-readable `name` property but is still addressed by `id`.** The `name` is how the query is invoked in public-facing resource URLs; the API resource itself is addressed by a minted GUID `id`.

## Compact URIs

Expand Down
3 changes: 2 additions & 1 deletion src/src/content/docs/api-doc/queues.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,11 @@ This endpoint acts in the same way as `/customers/{customer}/queue`, but any bat

`/customers/{customer}/queue/priority`

Note that GET is not supported. Batches sent to the priority queue will be visible in the batch collections available on the main queue: [batches](#batches), [active](#active) and [recent](#recent). The only difference is that they will be picked up and processed sooner when sent to the priority queue - so a batch may appear sooner in [recent](#recent).
A GET returns the priority queue's own CustomerQueue resource, with its counts. Batches sent to the priority queue will also be visible in the batch collections available on the main queue: [batches](#batches), [active](#active) and [recent](#recent). The only difference is that they will be picked up and processed sooner when sent to the priority queue - so a batch may appear sooner in [recent](#recent).

| Method | Label | Expects | Returns | Status |
|:---|:---|:---|:---|:---|
| GET | View the priority queue | - | vocab:CustomerQueue | 200 OK, 404 Not Found |
| POST | Submit a collection of Assets (vocab:Image) and get a batch back | hydra:Collection | vocab:Batch | 201 Created |

<Aside type="caution">
Expand Down
Loading